Repository: mojohaus/versions
Pull request #1202 (2024-12-24 11:11:46)

Refactoring: coalesce use-*-* goals.
I wanted to try and do something similar to what mojohaus/versions#292 was, but since the plugin has moved on, it first needs some refactoring.

This PR makes the use-\*-\* goals use shared codebase in order to make future refactoring simpler.


Patch:
diff --git a/.github/workflows/pr-automation.yml b/.github/workflows/pr-automation.yml
index d6af17f2..11f193d5 100644
--- a/.github/workflows/pr-automation.yml
+++ b/.github/workflows/pr-automation.yml
@@ -17,14 +17,11 @@
 
 name: PR Automation
 on:
-  pull_request:
+  pull_request_target:
     types:
       - closed
       - unlabeled
       - demilestoned
-  pull_request_review:
-    types:
-      - submitted
 
 jobs:
   pr-automation:
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsDependencyUpdaterMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsDependencyUpdaterMojo.java
index a7d794b8..8428c9f2 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsDependencyUpdaterMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsDependencyUpdaterMojo.java
@@ -23,6 +23,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.regex.Pattern;
 
 import org.apache.commons.lang3.StringUtils;
@@ -228,15 +229,12 @@ public abstract class AbstractVersionsDependencyUpdaterMojo extends AbstractVers
      * @since 1.0-alpha-3
      */
     protected Artifact findArtifact(Dependency dependency) {
-        if (getProject().getDependencyArtifacts() == null) {
-            return null;
-        }
-        for (Artifact artifact : getProject().getDependencyArtifacts()) {
-            if (compare(artifact, dependency)) {
-                return artifact;
-            }
-        }
-        return null;
+        return Optional.ofNullable(getProject().getDependencyArtifacts())
+                // no mutation, so parallelStream is safe
+                .flatMap(artifacts -> artifacts.parallelStream()
+                        .filter(artifact -> compare(artifact, dependency))
+                        .findAny())
+                .orElse(null);
     }
 
     /**
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java
index f394adcb..43e92914 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java
@@ -123,13 +123,7 @@ public abstract class AbstractVersionsUpdaterMojo extends AbstractMojo {
     @Parameter(property = "generateBackupPoms", defaultValue = "true")
     protected boolean generateBackupPoms;
 
-    /**
-     * Whether to allow snapshots when searching for the latest version of an artifact.
-     *
-     * @since 1.0-alpha-1
-     */
-    @Parameter(property = "allowSnapshots", defaultValue = "false")
-    protected boolean allowSnapshots;
+    protected abstract boolean isAllowSnapshots();
 
     /**
      * Our versions helper.
@@ -296,7 +290,7 @@ public abstract class AbstractVersionsUpdaterMojo extends AbstractMojo {
     protected ArtifactVersion findLatestVersion(
             Artifact artifact, VersionRange versionRange, Boolean allowingSnapshots, boolean usePluginRepositories)
             throws MojoExecutionException, VersionRetrievalException {
-        boolean includeSnapshots = allowingSnapshots != null ? allowingSnapshots : this.allowSnapshots;
+        boolean includeSnapshots = allowingSnapshots != null ? allowingSnapshots : isAllowSnapshots();
         final ArtifactVersions artifactVersions =
                 getHelper().lookupArtifactVersions(artifact, versionRange, usePluginRepositories);
         return artifactVersions.getNewestVersion(versionRange, null, includeSnapshots, false);
@@ -437,7 +431,7 @@ public abstract class AbstractVersionsUpdaterMojo extends AbstractMojo {
         ArtifactVersion winner = version.getNewestVersion(
                 currentVersion,
                 property,
-                this.allowSnapshots,
+                isAllowSnapshots(),
                 this.reactorProjects,
                 this.getHelper(),
                 allowDowngrade,
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java
index 43c9e0b0..a2ab3245 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java
@@ -116,6 +116,12 @@ public class CompareDependenciesMojo extends AbstractVersionsDependencyUpdaterMo
     @Parameter(property = "reportOutputFile")
     protected File reportOutputFile;
 
+    @Override
+    protected boolean isAllowSnapshots() {
+        // this parameter is used by base class, but shouldn't affect comparison; setting to true
+        return true;
+    }
+
     /**
      * The (injected) instance of {@link ProjectBuilder}
      *
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayDependencyUpdatesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayDependencyUpdatesMojo.java
index 9cf5be21..643c716d 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayDependencyUpdatesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayDependencyUpdatesMojo.java
@@ -310,6 +310,19 @@ public class DisplayDependencyUpdatesMojo extends AbstractVersionsDisplayMojo {
     @Parameter(property = "pluginManagementDependencyExcludes")
     private List<String> pluginManagementDependencyExcludes;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     // --------------------- GETTER / SETTER METHODS ---------------------
 
     @Inject
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayExtensionUpdatesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayExtensionUpdatesMojo.java
index 16ecde53..c79bfbd9 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayExtensionUpdatesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayExtensionUpdatesMojo.java
@@ -145,6 +145,19 @@ public class DisplayExtensionUpdatesMojo extends AbstractVersionsDisplayMojo {
     @Parameter(property = "verbose", defaultValue = "false")
     private boolean verbose;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     @Inject
     public DisplayExtensionUpdatesMojo(
             ArtifactHandlerManager artifactHandlerManager,
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayParentUpdatesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayParentUpdatesMojo.java
index fa7f1b97..51267cff 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayParentUpdatesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayParentUpdatesMojo.java
@@ -131,6 +131,19 @@ public class DisplayParentUpdatesMojo extends AbstractVersionsDisplayMojo {
     @Parameter(property = "allowIncrementalUpdates", defaultValue = "true")
     protected boolean allowIncrementalUpdates = true;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     // -------------------------- OTHER METHODS --------------------------
 
     @Inject
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java
index 324bda28..12034930 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java
@@ -171,6 +171,19 @@ public class DisplayPluginUpdatesMojo extends AbstractVersionsDisplayMojo {
     @Parameter(property = "processUnboundPlugins", defaultValue = "false")
     protected boolean processUnboundPlugins;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     // --------------------- GETTER / SETTER METHODS ---------------------
 
     @Inject
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojo.java
index 28663868..545db1d2 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojo.java
@@ -139,6 +139,19 @@ public class DisplayPropertyUpdatesMojo extends AbstractVersionsDisplayMojo {
     @Parameter(property = "includeParent", defaultValue = "false")
     protected boolean includeParent;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     // -------------------------- STATIC METHODS --------------------------
 
     // -------------------------- OTHER METHODS --------------------------
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ForceReleasesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ForceReleasesMojo.java
index 5474d349..5b3625c0 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ForceReleasesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ForceReleasesMojo.java
@@ -60,6 +60,11 @@ public class ForceReleasesMojo extends AbstractVersionsDependencyUpdaterMojo {
     @Parameter(property = "failIfNotReplaced", defaultValue = "false")
     protected boolean failIfNotReplaced;
 
+    @Override
+    protected boolean isAllowSnapshots() {
+        return false;
+    }
+
     // ------------------------------ METHODS --------------------------
 
     @Inject
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/LockSnapshotsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/LockSnapshotsMojo.java
index 474a688f..6b03e72c 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/LockSnapshotsMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/LockSnapshotsMojo.java
@@ -69,6 +69,12 @@ public class LockSnapshotsMojo extends AbstractVersionsDependencyUpdaterMojo {
 
     // ------------------------------ METHODS --------------------------
 
+    @Override
+    protected boolean isAllowSnapshots() {
+        // used by base method; must be true so that it's able to select snapshots
+        return true;
+    }
+
     @Inject
     public LockSnapshotsMojo(
             ArtifactHandlerManager artifactHandlerManager,
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ResolveRangesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ResolveRangesMojo.java
index 35ab9e1d..a92d0b43 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ResolveRangesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ResolveRangesMojo.java
@@ -121,6 +121,19 @@ public class ResolveRangesMojo extends AbstractVersionsDependencyUpdaterMojo {
     @Parameter(property = "allowIncrementalUpdates", defaultValue = "true")
     private boolean allowIncrementalUpdates;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     // ------------------------------ FIELDS ------------------------------
 
     /**
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java
index baa70fcf..668fee2e 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java
@@ -239,6 +239,19 @@ public class SetMojo extends AbstractVersionsUpdaterMojo {
     @Parameter(property = "updateBuildOutputTimestampPolicy", defaultValue = "onchange")
     private String updateBuildOutputTimestampPolicy;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     /**
      * The changes to module coordinates. Guarded by this.
      */
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetPropertyMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetPropertyMojo.java
index ddf5d9ec..54279500 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetPropertyMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetPropertyMojo.java
@@ -94,6 +94,19 @@ public class SetPropertyMojo extends AbstractVersionsUpdaterMojo {
     @Parameter(property = "profileId")
     private String profileId = null;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     @Inject
     public SetPropertyMojo(
             ArtifactHandlerManager artifactHandlerManager,
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetScmTagMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetScmTagMojo.java
index e9e51338..1b72bbe3 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetScmTagMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetScmTagMojo.java
@@ -64,6 +64,19 @@ public class SetScmTagMojo extends AbstractVersionsUpdaterMojo {
     @Parameter(property = "url")
     private String url;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     @Inject
     public SetScmTagMojo(
             ArtifactHandlerManager artifactHandlerManager,
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UnlockSnapshotsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UnlockSnapshotsMojo.java
index 259215fd..404dfe73 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UnlockSnapshotsMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UnlockSnapshotsMojo.java
@@ -61,6 +61,12 @@ public class UnlockSnapshotsMojo extends AbstractVersionsDependencyUpdaterMojo {
 
     // ------------------------------ METHODS --------------------------
 
+    @Override
+    protected boolean isAllowSnapshots() {
+        // used by base class; must be true so that it can select snapshots
+        return true;
+    }
+
     @Inject
     public UnlockSnapshotsMojo(
             ArtifactHandlerManager artifactHandlerManager,
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateChildModulesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateChildModulesMojo.java
index 4aa331ed..3c3da89b 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateChildModulesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateChildModulesMojo.java
@@ -35,6 +35,7 @@ import org.apache.maven.model.Parent;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.wagon.Wagon;
 import org.codehaus.mojo.versions.api.PomHelper;
 import org.codehaus.mojo.versions.api.recording.ChangeRecorder;
@@ -65,6 +66,19 @@ public class UpdateChildModulesMojo extends AbstractVersionsUpdaterMojo {
      */
     private transient String sourceVersion = null;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     @Inject
     public UpdateChildModulesMojo(
             ArtifactHandlerManager artifactHandlerManager,
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java
index 32b76113..87ba243f 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java
@@ -130,6 +130,19 @@ public class UpdateParentMojo extends AbstractVersionsUpdaterMojo {
     @Parameter(property = "allowIncrementalUpdates", defaultValue = "true")
     protected boolean allowIncrementalUpdates = true;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     // -------------------------- OTHER METHODS --------------------------
 
     @Inject
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojoBase.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojoBase.java
index b567eceb..9494d420 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojoBase.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojoBase.java
@@ -107,6 +107,19 @@ public abstract class UpdatePropertiesMojoBase extends AbstractVersionsDependenc
     @Parameter(property = "includeParent", defaultValue = "true")
     protected boolean includeParent = true;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     public UpdatePropertiesMojoBase(
             ArtifactHandlerManager artifactHandlerManager,
             RepositorySystem repositorySystem,
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseDepVersionMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseDepVersionMojo.java
index f195da38..40f14d75 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseDepVersionMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseDepVersionMojo.java
@@ -90,6 +90,19 @@ public class UseDepVersionMojo extends AbstractVersionsDependencyUpdaterMojo {
     @Parameter(property = "forceVersion", defaultValue = "false")
     protected boolean forceVersion;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     /**
      * <p>Will augment normal processing by, if a dependency value is set using a property, trying to update
      * the value of the property.</p>
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextReleasesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextReleasesMojo.java
index b71f25e7..9f77f5dc 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextReleasesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextReleasesMojo.java
@@ -16,35 +16,21 @@ package org.codehaus.mojo.versions;
  */
 
 import javax.inject.Inject;
-import javax.xml.stream.XMLStreamException;
 
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Stream;
 
+import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.wagon.Wagon;
-import org.codehaus.mojo.versions.api.PomHelper;
-import org.codehaus.mojo.versions.api.VersionRetrievalException;
 import org.codehaus.mojo.versions.api.recording.ChangeRecorder;
-import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord;
-import org.codehaus.mojo.versions.ordering.InvalidSegmentException;
-import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader;
 import org.eclipse.aether.RepositorySystem;
 
-import static java.util.Collections.singletonList;
-import static org.codehaus.mojo.versions.api.recording.DependencyChangeRecord.ChangeKind.DEPENDENCY;
-import static org.codehaus.mojo.versions.api.recording.DependencyChangeRecord.ChangeKind.DEPENDENCY_MANAGEMENT;
-import static org.codehaus.mojo.versions.api.recording.DependencyChangeRecord.ChangeKind.PARENT;
-
 /**
  * Replaces any release versions with the next release version (if it has been released).
  *
@@ -73,55 +59,43 @@ public class UseNextReleasesMojo extends UseLatestVersionsMojoBase {
         super(artifactHandlerManager, repositorySystem, wagonMap, changeRecorders);
     }
 
-    /**
-     * @param pom the pom to update.
-     * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong
-     * @throws org.apache.maven.plugin.MojoFailureException when things go wrong in a very bad way
-     * @throws javax.xml.stream.XMLStreamException when things go wrong with XML streaming
-     * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader)
-     */
-    protected void update(MutableXMLStreamReader pom)
-            throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException {
-        try {
-            if (isProcessingDependencyManagement()) {
-                DependencyManagement dependencyManagement =
-                        PomHelper.getRawModel(getProject()).getDependencyManagement();
-                if (dependencyManagement != null) {
-                    useNextReleases(pom, dependencyManagement.getDependencies(), DEPENDENCY_MANAGEMENT);
-                }
-            }
+    @Override
+    protected boolean isAllowMajorUpdates() {
+        return true;
+    }
 
-            if (getProject().getDependencies() != null && isProcessingDependencies()) {
-                useNextReleases(pom, getProject().getDependencies(), DEPENDENCY);
-            }
+    @Override
+    protected boolean isAllowMinorUpdates() {
+        return true;
+    }
+
+    @Override
+    protected boolean isAllowIncrementalUpdates() {
+        return true;
+    }
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return false;
+    }
+
+    @Override
+    protected boolean isAllowDowngrade() {
+        return allowDowngrade;
+    }
+
+    @Override
+    protected boolean updateFilter(Dependency dep) {
+        return allowDowngrade || !ArtifactUtils.isSnapshot(dep.getVersion());
+    }
 
-            if (getProject().getParent() != null && isProcessingParent()) {
-                useNextReleases(pom, singletonList(getParentDependency()), PARENT);
-            }
-        } catch (IOException e) {
-            throw new MojoExecutionException(e.getMessage(), e);
-        }
+    @Override
+    protected boolean artifactVersionsFilter(ArtifactVersion ver) {
+        return true;
     }
 
-    private void useNextReleases(
-            MutableXMLStreamReader pom,
-            Collection<Dependency> dependencies,
-            DependencyChangeRecord.ChangeKind changeKind)
-            throws XMLStreamException, MojoExecutionException, VersionRetrievalException {
-        useLatestVersions(
-                pom,
-                dependencies,
-                (dep, versions) -> {
-                    try {
-                        return Arrays.stream(versions.getNewerVersions(
-                                        dep.getVersion(), Optional.empty(), false, allowDowngrade))
-                                .findFirst();
-                    } catch (InvalidSegmentException e) {
-                        throw new RuntimeException(e);
-                    }
-                },
-                changeKind,
-                dep -> allowDowngrade
-                        || !SNAPSHOT_REGEX.matcher(dep.getVersion()).matches());
+    @Override
+    protected Optional<ArtifactVersion> versionProducer(Stream<ArtifactVersion> stream) {
+        return stream.findFirst();
     }
 }
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextSnapshotsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextSnapshotsMojo.java
index de093e7a..28e6f4ec 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextSnapshotsMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextSnapshotsMojo.java
@@ -16,39 +16,21 @@ package org.codehaus.mojo.versions;
  */
 
 import javax.inject.Inject;
-import javax.xml.stream.XMLStreamException;
 
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Stream;
 
+import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.wagon.Wagon;
-import org.codehaus.mojo.versions.api.PomHelper;
-import org.codehaus.mojo.versions.api.Segment;
-import org.codehaus.mojo.versions.api.VersionRetrievalException;
 import org.codehaus.mojo.versions.api.recording.ChangeRecorder;
-import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord;
-import org.codehaus.mojo.versions.ordering.InvalidSegmentException;
-import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader;
 import org.eclipse.aether.RepositorySystem;
 
-import static java.util.Collections.singletonList;
-import static java.util.Optional.empty;
-import static java.util.Optional.of;
-import static org.codehaus.mojo.versions.api.Segment.INCREMENTAL;
-import static org.codehaus.mojo.versions.api.Segment.MAJOR;
-import static org.codehaus.mojo.versions.api.Segment.MINOR;
-
 /**
  * Replaces any release versions with the next snapshot version (if it has been deployed).
  *
@@ -94,80 +76,45 @@ public class UseNextSnapshotsMojo extends UseLatestVersionsMojoBase {
             Map<String, Wagon> wagonMap,
             Map<String, ChangeRecorder> changeRecorders) {
         super(artifactHandlerManager, repositorySystem, wagonMap, changeRecorders);
-        // the below is necessary for UseLatestVersionsMojoBase.useLatestVersions to select snapshots
-        allowSnapshots = true;
     }
 
-    /**
-     * @param pom the pom to update.
-     * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong
-     * @throws org.apache.maven.plugin.MojoFailureException   when things go wrong in a very bad way
-     * @throws javax.xml.stream.XMLStreamException            when things go wrong with XML streaming
-     * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader)
-     */
-    protected void update(MutableXMLStreamReader pom)
-            throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException {
-        try {
-            DependencyManagement dependencyManagement =
-                    PomHelper.getRawModel(getProject()).getDependencyManagement();
-            if (dependencyManagement != null) {
-                useNextSnapshots(
-                        pom,
-                        dependencyManagement.getDependencies(),
-                        DependencyChangeRecord.ChangeKind.DEPENDENCY_MANAGEMENT);
-            }
-            if (getProject().getDependencies() != null && isProcessingDependencies()) {
-                useNextSnapshots(pom, getProject().getDependencies(), DependencyChangeRecord.ChangeKind.DEPENDENCY);
-            }
-            if (getProject().getParent() != null && isProcessingParent()) {
-                useNextSnapshots(pom, singletonList(getParentDependency()), DependencyChangeRecord.ChangeKind.PARENT);
-            }
-        } catch (IOException e) {
-            throw new MojoExecutionException(e.getMessage(), e);
-        }
+    @Override
+    protected boolean isAllowMajorUpdates() {
+        return allowMajorUpdates;
+    }
+
+    @Override
+    protected boolean isAllowMinorUpdates() {
+        return allowMinorUpdates;
+    }
+
+    @Override
+    protected boolean isAllowIncrementalUpdates() {
+        return allowIncrementalUpdates;
+    }
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return true;
+    }
+
+    @Override
+    protected boolean isAllowDowngrade() {
+        return false;
+    }
+
+    @Override
+    protected boolean updateFilter(Dependency dep) {
+        return !ArtifactUtils.isSnapshot(dep.getVersion());
+    }
+
+    @Override
+    protected boolean artifactVersionsFilter(ArtifactVersion ver) {
+        return ArtifactUtils.isSnapshot(ver.toString());
     }
 
-    private void useNextSnapshots(
-            MutableXMLStreamReader pom,
-            Collection<Dependency> dependencies,
-            DependencyChangeRecord.ChangeKind changeKind)
-            throws XMLStreamException, MojoExecutionException, VersionRetrievalException {
-        Log log = getLog();
-        if (log != null && !allowIncrementalUpdates) {
-            log.info("Assuming allowMinorUpdates false because allowIncrementalUpdates is false.");
-        }
-
-        if (log != null && !allowMinorUpdates) {
-            log.info("Assuming allowMajorUpdates false because allowMinorUpdates is false.");
-        }
-
-        Optional<Segment> unchangedSegment = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates
-                ? empty()
-                : allowMinorUpdates && allowIncrementalUpdates
-                        ? of(MAJOR)
-                        : allowIncrementalUpdates ? of(MINOR) : of(INCREMENTAL);
-        if (log != null && log.isDebugEnabled()) {
-            log.debug(unchangedSegment
-                            .map(Segment::minorTo)
-                            .map(Segment::toString)
-                            .orElse("ALL") + " version changes allowed");
-        }
-
-        useLatestVersions(
-                pom,
-                dependencies,
-                (dep, versions) -> {
-                    try {
-                        return Arrays.stream(versions.getNewerVersions(dep.getVersion(), unchangedSegment, true, false))
-                                .filter(v ->
-                                        SNAPSHOT_REGEX.matcher(v.toString()).matches())
-                                .findFirst();
-                    } catch (InvalidSegmentException e) {
-                        getLog().info("Ignoring " + toString(dep) + " as the version number is too short");
-                        return empty();
-                    }
-                },
-                changeKind,
-                dep -> !SNAPSHOT_REGEX.matcher(dep.getVersion()).matches());
+    @Override
+    protected Optional<ArtifactVersion> versionProducer(Stream<ArtifactVersion> stream) {
+        return stream.findFirst();
     }
 }
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextVersionsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextVersionsMojo.java
index ab548076..308cdfb9 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextVersionsMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextVersionsMojo.java
@@ -16,35 +16,20 @@ package org.codehaus.mojo.versions;
  */
 
 import javax.inject.Inject;
-import javax.xml.stream.XMLStreamException;
 
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Stream;
 
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.wagon.Wagon;
-import org.codehaus.mojo.versions.api.PomHelper;
-import org.codehaus.mojo.versions.api.VersionRetrievalException;
 import org.codehaus.mojo.versions.api.recording.ChangeRecorder;
-import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord;
-import org.codehaus.mojo.versions.ordering.InvalidSegmentException;
-import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader;
 import org.eclipse.aether.RepositorySystem;
 
-import static java.util.Collections.singletonList;
-import static org.codehaus.mojo.versions.api.recording.DependencyChangeRecord.ChangeKind.DEPENDENCY;
-import static org.codehaus.mojo.versions.api.recording.DependencyChangeRecord.ChangeKind.DEPENDENCY_MANAGEMENT;
-import static org.codehaus.mojo.versions.api.recording.DependencyChangeRecord.ChangeKind.PARENT;
-
 /**
  * Replaces any version with the latest version.
  *
@@ -64,6 +49,19 @@ public class UseNextVersionsMojo extends UseLatestVersionsMojoBase {
     @Parameter(property = "allowDowngrade", defaultValue = "false")
     protected boolean allowDowngrade;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     // ------------------------------ METHODS --------------------------
 
     @Inject
@@ -75,51 +73,38 @@ public class UseNextVersionsMojo extends UseLatestVersionsMojoBase {
         super(artifactHandlerManager, repositorySystem, wagonMap, changeRecorders);
     }
 
-    /**
-     * @param pom the pom to update.
-     * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong
-     * @throws org.apache.maven.plugin.MojoFailureException   when things go wrong in a very bad way
-     * @throws javax.xml.stream.XMLStreamException            when things go wrong with XML streaming
-     * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader)
-     */
-    protected void update(MutableXMLStreamReader pom)
-            throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException {
-        try {
-            if (isProcessingDependencyManagement()) {
-                DependencyManagement dependencyManagement =
-                        PomHelper.getRawModel(getProject()).getDependencyManagement();
-                if (dependencyManagement != null) {
-                    useNextVersions(pom, dependencyManagement.getDependencies(), DEPENDENCY_MANAGEMENT);
-                }
-            }
-            if (getProject().getDependencies() != null && isProcessingDependencies()) {
-                useNextVersions(pom, getProject().getDependencies(), DEPENDENCY);
-            }
-            if (getProject().getParent() != null && isProcessingParent()) {
-                useNextVersions(pom, singletonList(getParentDependency()), PARENT);
-            }
-        } catch (IOException e) {
-            throw new MojoExecutionException(e.getMessage(), e);
-        }
+    @Override
+    protected boolean isAllowMajorUpdates() {
+        return true;
+    }
+
+    @Override
+    protected boolean isAllowMinorUpdates() {
+        return true;
+    }
+
+    @Override
+    protected boolean isAllowIncrementalUpdates() {
+        return true;
+    }
+
+    @Override
+    protected boolean isAllowDowngrade() {
+        return allowDowngrade;
+    }
+
+    @Override
+    protected boolean updateFilter(Dependency dep) {
+        return true;
+    }
+
+    @Override
+    protected boolean artifactVersionsFilter(ArtifactVersion ver) {
+        return true;
     }
 
-    private void useNextVersions(
-            MutableXMLStreamReader pom,
-            Collection<Dependency> dependencies,
-            DependencyChangeRecord.ChangeKind changeKind)
-            throws XMLStreamException, MojoExecutionException, VersionRetrievalException {
-        useLatestVersions(
-                pom,
-                dependencies,
-                (dep, versions) -> {
-                    try {
-                        return Arrays.stream(versions.getNewerVersions(
-                                        dep.getVersion(), Optional.empty(), allowSnapshots, allowDowngrade))
-                                .findFirst();
-                    } catch (InvalidSegmentException e) {
-                        throw new RuntimeException(e);
-                    }
-                },
-                changeKind);
+    @Override
+    protected Optional<ArtifactVersion> versionProducer(Stream<ArtifactVersion> stream) {
+        return stream.findFirst();
     }
 }
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReactorMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReactorMojo.java
index 3fd045f2..65044dca 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReactorMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReactorMojo.java
@@ -34,6 +34,7 @@ import org.apache.maven.model.DependencyManagement;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.wagon.Wagon;
 import org.codehaus.mojo.versions.api.PomHelper;
@@ -51,6 +52,19 @@ import org.eclipse.aether.RepositorySystem;
 @Mojo(name = "use-reactor", threadSafe = true)
 public class UseReactorMojo extends AbstractVersionsDependencyUpdaterMojo {
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     // ------------------------------ METHODS --------------------------
 
     @Inject
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReleasesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReleasesMojo.java
index ce1249f2..19de874a 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReleasesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReleasesMojo.java
@@ -74,6 +74,11 @@ public class UseReleasesMojo extends AbstractVersionsDependencyUpdaterMojo {
     @Parameter(property = "failIfNotReplaced", defaultValue = "false")
     protected boolean failIfNotReplaced;
 
+    @Override
+    protected boolean isAllowSnapshots() {
+        return false;
+    }
+
     // ------------------------------ METHODS --------------------------
 
     @Inject


Test patch:
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestReleasesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestReleasesMojo.java
index 05faf428..d356bba2 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestReleasesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestReleasesMojo.java
@@ -16,44 +16,22 @@ package org.codehaus.mojo.versions;
  */
 
 import javax.inject.Inject;
-import javax.xml.stream.XMLStreamException;
 
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
+import java.util.Comparator;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Stream;
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.DefaultArtifact;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
+import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
 import org.apache.maven.artifact.versioning.ArtifactVersion;
-import org.apache.maven.artifact.versioning.VersionRange;
 import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.wagon.Wagon;
-import org.codehaus.mojo.versions.api.PomHelper;
-import org.codehaus.mojo.versions.api.Segment;
-import org.codehaus.mojo.versions.api.VersionRetrievalException;
 import org.codehaus.mojo.versions.api.recording.ChangeRecorder;
-import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord;
-import org.codehaus.mojo.versions.ordering.InvalidSegmentException;
-import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader;
 import org.eclipse.aether.RepositorySystem;
 
-import static java.util.Collections.singletonList;
-import static java.util.Optional.empty;
-import static java.util.Optional.of;
-import static org.codehaus.mojo.versions.api.Segment.INCREMENTAL;
-import static org.codehaus.mojo.versions.api.Segment.MAJOR;
-import static org.codehaus.mojo.versions.api.Segment.MINOR;
-
 /**
  * Replaces any <em>release</em> versions (i.e. versions that are not snapshots and do not
  * have a year-month-day suffix) with the latest <em>release</em> version. This goal
@@ -118,105 +96,42 @@ public class UseLatestReleasesMojo extends UseLatestVersionsMojoBase {
         super(artifactHandlerManager, repositorySystem, wagonMap, changeRecorders);
     }
 
-    /**
-     * @param pom the pom to update.
-     * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong
-     * @throws org.apache.maven.plugin.MojoFailureException   when things go wrong in a very bad way
-     * @throws javax.xml.stream.XMLStreamException            when things go wrong with XML streaming
-     * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader)
-     */
-    protected void update(MutableXMLStreamReader pom)
-            throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException {
-        try {
-            if (isProcessingDependencyManagement()) {
-                DependencyManagement dependencyManagement =
-                        PomHelper.getRawModel(getProject()).getDependencyManagement();
-                if (dependencyManagement != null) {
-                    useLatestReleases(
-                            pom,
-                            dependencyManagement.getDependencies(),
-                            DependencyChangeRecord.ChangeKind.DEPENDENCY_MANAGEMENT);
-                }
-            }
-            if (getProject().getDependencies() != null && isProcessingDependencies()) {
-                useLatestReleases(pom, getProject().getDependencies(), DependencyChangeRecord.ChangeKind.DEPENDENCY);
-            }
-            if (getProject().getParent() != null && isProcessingParent()) {
-                useLatestReleases(pom, singletonList(getParentDependency()), DependencyChangeRecord.ChangeKind.PARENT);
-            }
-        } catch (IOException e) {
-            throw new MojoExecutionException(e.getMessage(), e);
-        }
+    @Override
+    protected final boolean isAllowMajorUpdates() {
+        return allowMajorUpdates;
     }
 
-    private void useLatestReleases(
-            MutableXMLStreamReader pom,
-            Collection<Dependency> dependencies,
-            DependencyChangeRecord.ChangeKind changeKind)
-            throws XMLStreamException, MojoExecutionException, VersionRetrievalException {
-        Log log = getLog();
-        if (log != null && !allowIncrementalUpdates) {
-            log.info("Assuming allowMinorUpdates false because allowIncrementalUpdates is false.");
-        }
-
-        if (log != null && !allowMinorUpdates) {
-            log.info("Assuming allowMajorUpdates false because allowMinorUpdates is false.");
-        }
-
-        Optional<Segment> unchangedSegment = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates
-                ? empty()
-                : allowMinorUpdates && allowIncrementalUpdates
-                        ? of(MAJOR)
-                        : allowIncrementalUpdates ? of(MINOR) : of(INCREMENTAL);
-        if (log != null && log.isDebugEnabled()) {
-            log.debug(unchangedSegment
-                            .map(Segment::minorTo)
-                            .map(Segment::toString)
-                            .orElse("ALL") + " version changes allowed");
-        }
-
-        useLatestVersions(
-                pom,
-                dependencies,
-                (dep, versions) -> {
-                    try {
-                        return getLastFiltered(
-                                versions.getNewerVersions(dep.getVersion(), unchangedSegment, false, allowDowngrade),
-                                dep);
-                    } catch (InvalidSegmentException e) {
-                        getLog().warn(String.format(
-                                "Skipping the processing of %s:%s:%s due to: %s",
-                                dep.getGroupId(), dep.getArtifactId(), dep.getVersion(), e.getMessage()));
-                    }
-                    return empty();
-                },
-                changeKind,
-                dep -> allowDowngrade
-                        || !SNAPSHOT_REGEX.matcher(dep.getVersion()).matches());
+    @Override
+    protected final boolean isAllowMinorUpdates() {
+        return allowMinorUpdates;
     }
 
-    /**
-     * Returns the last element of the given {@link ArtifactVersion} array such as every version of the array
-     * is included in the {@code includes} and excluded by the {@code excludes} filters
-     *
-     * @param newer array of {@link ArtifactVersion} with newer versions
-     * @param dependency dependency prototype to create the artifacts from
-     * @return the newest version fulfilling the criteria
-     */
-    private Optional<ArtifactVersion> getLastFiltered(ArtifactVersion[] newer, Dependency dependency) {
-        return Arrays.stream(newer)
-                .filter(version -> {
-                    Artifact artefactWithNewVersion = new DefaultArtifact(
-                            dependency.getGroupId(),
-                            dependency.getArtifactId(),
-                            VersionRange.createFromVersion(version.toString()),
-                            dependency.getScope(),
-                            dependency.getType(),
-                            null,
-                            new DefaultArtifactHandler(),
-                            false);
-                    return isIncluded(artefactWithNewVersion);
-                })
-                .reduce((v1, v2) -> v2);
+    @Override
+    protected final boolean isAllowIncrementalUpdates() {
+        return allowIncrementalUpdates;
+    }
+
+    @Override
+    protected final boolean isAllowSnapshots() {
+        return false;
+    }
+
+    @Override
+    protected final boolean isAllowDowngrade() {
+        return allowDowngrade;
+    }
+
+    @Override
+    protected boolean updateFilter(Dependency dep) {
+        return isAllowDowngrade() || !ArtifactUtils.isSnapshot(dep.getVersion());
+    }
+
+    @Override
+    protected boolean artifactVersionsFilter(ArtifactVersion ver) {
+        return true;
+    }
+
+    protected Optional<ArtifactVersion> versionProducer(Stream<ArtifactVersion> stream) {
+        return stream.max(Comparator.naturalOrder());
     }
 }
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestSnapshotsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestSnapshotsMojo.java
index dad91375..906cf197 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestSnapshotsMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestSnapshotsMojo.java
@@ -16,40 +16,22 @@ package org.codehaus.mojo.versions;
  */
 
 import javax.inject.Inject;
-import javax.xml.stream.XMLStreamException;
 
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.Comparator;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Stream;
 
+import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.wagon.Wagon;
-import org.codehaus.mojo.versions.api.PomHelper;
-import org.codehaus.mojo.versions.api.Segment;
-import org.codehaus.mojo.versions.api.VersionRetrievalException;
 import org.codehaus.mojo.versions.api.recording.ChangeRecorder;
-import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord;
-import org.codehaus.mojo.versions.ordering.InvalidSegmentException;
-import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader;
 import org.eclipse.aether.RepositorySystem;
 
-import static java.util.Collections.singletonList;
-import static java.util.Optional.empty;
-import static java.util.Optional.of;
-import static org.codehaus.mojo.versions.api.Segment.INCREMENTAL;
-import static org.codehaus.mojo.versions.api.Segment.MAJOR;
-import static org.codehaus.mojo.versions.api.Segment.MINOR;
-
 /**
  * Replaces any release versions with the latest snapshot version (if it has been deployed).
  *
@@ -97,78 +79,43 @@ public class UseLatestSnapshotsMojo extends UseLatestVersionsMojoBase {
         super(artifactHandlerManager, repositorySystem, wagonMap, changeRecorders);
     }
 
-    /**
-     * @param pom the pom to update.
-     * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong
-     * @throws org.apache.maven.plugin.MojoFailureException   when things go wrong in a very bad way
-     * @throws javax.xml.stream.XMLStreamException            when things go wrong with XML streaming
-     * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader)
-     */
-    protected void update(MutableXMLStreamReader pom)
-            throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException {
-        try {
-            if (isProcessingDependencyManagement()) {
-                DependencyManagement dependencyManagement =
-                        PomHelper.getRawModel(getProject()).getDependencyManagement();
-                if (dependencyManagement != null) {
-                    useLatestSnapshots(
-                            pom,
-                            dependencyManagement.getDependencies(),
-                            DependencyChangeRecord.ChangeKind.DEPENDENCY_MANAGEMENT);
-                }
-            }
-            if (getProject().getDependencies() != null && isProcessingDependencies()) {
-                useLatestSnapshots(pom, getProject().getDependencies(), DependencyChangeRecord.ChangeKind.DEPENDENCY);
-            }
-            if (getProject().getParent() != null && isProcessingParent()) {
-                useLatestSnapshots(pom, singletonList(getParentDependency()), DependencyChangeRecord.ChangeKind.PARENT);
-            }
-        } catch (IOException e) {
-            throw new MojoExecutionException(e.getMessage(), e);
-        }
+    @Override
+    protected boolean isAllowMajorUpdates() {
+        return allowMajorUpdates;
+    }
+
+    @Override
+    protected boolean isAllowMinorUpdates() {
+        return allowMinorUpdates;
+    }
+
+    @Override
+    protected boolean isAllowIncrementalUpdates() {
+        return allowIncrementalUpdates;
+    }
+
+    @Override
+    protected final boolean updateFilter(Dependency dep) {
+        return !ArtifactUtils.isSnapshot(dep.getVersion());
+    }
+
+    @Override
+    protected final boolean artifactVersionsFilter(ArtifactVersion ver) {
+        return ArtifactUtils.isSnapshot(ver.toString());
+    }
+
+    @Override
+    protected Optional<ArtifactVersion> versionProducer(Stream<ArtifactVersion> stream) {
+        return stream.max(Comparator.naturalOrder());
+    }
+
+    @Override
+    protected final boolean isAllowSnapshots() {
+        return true;
     }
 
-    private void useLatestSnapshots(
-            MutableXMLStreamReader pom,
-            Collection<Dependency> dependencies,
-            DependencyChangeRecord.ChangeKind changeKind)
-            throws XMLStreamException, MojoExecutionException, VersionRetrievalException {
-        Log log = getLog();
-        if (log != null && !allowIncrementalUpdates) {
-            log.info("Assuming allowMinorUpdates false because allowIncrementalUpdates is false.");
-        }
-
-        if (log != null && !allowMinorUpdates) {
-            log.info("Assuming allowMajorUpdates false because allowMinorUpdates is false.");
-        }
-
-        Optional<Segment> unchangedSegment = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates
-                ? empty()
-                : allowMinorUpdates && allowIncrementalUpdates
-                        ? of(MAJOR)
-                        : allowIncrementalUpdates ? of(MINOR) : of(INCREMENTAL);
-        if (log != null && log.isDebugEnabled()) {
-            log.debug(unchangedSegment
-                            .map(Segment::minorTo)
-                            .map(Segment::toString)
-                            .orElse("ALL") + " version changes allowed");
-        }
-
-        useLatestVersions(
-                pom,
-                dependencies,
-                (dep, versions) -> {
-                    try {
-                        return Arrays.stream(versions.getNewerVersions(dep.getVersion(), unchangedSegment, true, false))
-                                .filter(v ->
-                                        SNAPSHOT_REGEX.matcher(v.toString()).matches())
-                                .max(Comparator.naturalOrder());
-                    } catch (InvalidSegmentException e) {
-                        getLog().info("Ignoring " + toString(dep) + " as the version number is too short");
-                        return empty();
-                    }
-                },
-                changeKind,
-                dep -> !SNAPSHOT_REGEX.matcher(dep.getVersion()).matches());
+    @Override
+    protected final boolean isAllowDowngrade() {
+        return false;
     }
 }
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojo.java
index 9b3669f7..56897e40 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojo.java
@@ -16,38 +16,21 @@ package org.codehaus.mojo.versions;
  */
 
 import javax.inject.Inject;
-import javax.xml.stream.XMLStreamException;
 
-import java.io.IOException;
-import java.util.Collection;
+import java.util.Comparator;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Stream;
 
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.wagon.Wagon;
-import org.codehaus.mojo.versions.api.PomHelper;
-import org.codehaus.mojo.versions.api.Segment;
-import org.codehaus.mojo.versions.api.VersionRetrievalException;
 import org.codehaus.mojo.versions.api.recording.ChangeRecorder;
-import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord;
-import org.codehaus.mojo.versions.ordering.InvalidSegmentException;
-import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader;
 import org.eclipse.aether.RepositorySystem;
 
-import static java.util.Collections.singletonList;
-import static java.util.Optional.empty;
-import static java.util.Optional.of;
-import static org.codehaus.mojo.versions.api.Segment.INCREMENTAL;
-import static org.codehaus.mojo.versions.api.Segment.MAJOR;
-import static org.codehaus.mojo.versions.api.Segment.MINOR;
-
 /**
  * Replaces any version with the latest version found in the artifactory.
  *
@@ -93,6 +76,19 @@ public class UseLatestVersionsMojo extends UseLatestVersionsMojoBase {
     @Parameter(property = "allowDowngrade", defaultValue = "false")
     private boolean allowDowngrade;
 
+    /**
+     * Whether to allow snapshots when searching for the latest version of an artifact.
+     *
+     * @since 1.0-alpha-1
+     */
+    @Parameter(property = "allowSnapshots", defaultValue = "false")
+    protected boolean allowSnapshots;
+
+    @Override
+    protected boolean isAllowSnapshots() {
+        return allowSnapshots;
+    }
+
     // ------------------------------ METHODS --------------------------
 
     @Inject
@@ -105,84 +101,37 @@ public class UseLatestVersionsMojo extends UseLatestVersionsMojoBase {
     }
 
     @Override
-    public void execute() throws MojoExecutionException, MojoFailureException {
-        if (allowDowngrade && allowSnapshots) {
-            throw new MojoExecutionException("allowDowngrade is only valid with allowSnapshots equal to false");
-        }
-        super.execute();
+    protected final boolean isAllowMajorUpdates() {
+        return allowMajorUpdates;
     }
 
-    /**
-     * @param pom the pom to update.
-     * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong
-     * @throws org.apache.maven.plugin.MojoFailureException   when things go wrong in a very bad way
-     * @throws javax.xml.stream.XMLStreamException            when things go wrong with XML streaming
-     * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader)
-     */
-    protected void update(MutableXMLStreamReader pom)
-            throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException {
-        try {
-            if (isProcessingDependencyManagement()) {
-                DependencyManagement dependencyManagement =
-                        PomHelper.getRawModel(getProject()).getDependencyManagement();
-                if (dependencyManagement != null) {
-                    useLatestVersions(
-                            pom,
-                            dependencyManagement.getDependencies(),
-                            DependencyChangeRecord.ChangeKind.DEPENDENCY_MANAGEMENT);
-                }
-            }
-            if (getProject().getDependencies() != null && isProcessingDependencies()) {
-                useLatestVersions(pom, getProject().getDependencies(), DependencyChangeRecord.ChangeKind.DEPENDENCY);
-            }
-            if (getProject().getParent() != null && isProcessingParent()) {
-                useLatestVersions(pom, singletonList(getParentDependency()), DependencyChangeRecord.ChangeKind.PARENT);
-            }
-        } catch (IOException e) {
-            throw new MojoExecutionException(e.getMessage(), e);
-        }
+    @Override
+    protected final boolean isAllowMinorUpdates() {
+        return allowMinorUpdates;
+    }
+
+    @Override
+    protected final boolean isAllowIncrementalUpdates() {
+        return allowIncrementalUpdates;
+    }
+
+    @Override
+    protected boolean isAllowDowngrade() {
+        return allowDowngrade;
+    }
+
+    @Override
+    protected boolean updateFilter(Dependency dep) {
+        return true;
+    }
+
+    @Override
+    protected boolean artifactVersionsFilter(ArtifactVersion ver) {
+        return true;
     }
 
-    private void useLatestVersions(
-            MutableXMLStreamReader pom,
-            Collection<Dependency> dependencies,
-            DependencyChangeRecord.ChangeKind changeKind)
-            throws XMLStreamException, MojoExecutionException, VersionRetrievalException {
-        Log log = getLog();
-        if (log != null && !allowIncrementalUpdates) {
-            log.info("Assuming allowMinorUpdates false because allowIncrementalUpdates is false.");
-        }
-
-        if (log != null && !allowMinorUpdates) {
-            log.info("Assuming allowMajorUpdates false because allowMinorUpdates is false.");
-        }
-
-        Optional<Segment> unchangedSegment = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates
-                ? empty()
-                : allowMinorUpdates && allowIncrementalUpdates
-                        ? of(MAJOR)
-                        : allowIncrementalUpdates ? of(MINOR) : of(INCREMENTAL);
-        if (log != null && log.isDebugEnabled()) {
-            log.debug(unchangedSegment
-                            .map(Segment::minorTo)
-                            .map(Segment::toString)
-                            .orElse("ALL") + " version changes allowed");
-        }
-
-        useLatestVersions(
-                pom,
-                dependencies,
-                (dep, versions) -> {
-                    try {
-                        return versions.getNewestVersion(
-                                dep.getVersion(), unchangedSegment, allowSnapshots, allowDowngrade);
-                    } catch (InvalidSegmentException e) {
-                        getLog().warn(String.format(
-                                "Skipping the processing of %s:%s:%s due to: %s",
-                                dep.getGroupId(), dep.getArtifactId(), dep.getVersion(), e.getMessage()));
-                    }
-                    return empty();
-                },
-                changeKind);
+    @Override
+    protected Optional<ArtifactVersion> versionProducer(Stream<ArtifactVersion> stream) {
+        return stream.max(Comparator.naturalOrder());
     }
 }
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojoBase.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojoBase.java
index c28897be..2a38e776 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojoBase.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojoBase.java
@@ -17,27 +17,35 @@ package org.codehaus.mojo.versions;
 
 import javax.xml.stream.XMLStreamException;
 
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
-import java.util.function.BiFunction;
-import java.util.function.Predicate;
+import java.util.stream.Stream;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
 import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.model.Dependency;
+import org.apache.maven.model.DependencyManagement;
 import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.wagon.Wagon;
 import org.codehaus.mojo.versions.api.ArtifactVersions;
+import org.codehaus.mojo.versions.api.PomHelper;
+import org.codehaus.mojo.versions.api.Segment;
 import org.codehaus.mojo.versions.api.VersionRetrievalException;
 import org.codehaus.mojo.versions.api.recording.ChangeRecorder;
 import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord;
+import org.codehaus.mojo.versions.ordering.InvalidSegmentException;
 import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader;
 import org.codehaus.mojo.versions.utils.DefaultArtifactVersionCache;
+import org.codehaus.mojo.versions.utils.SegmentUtils;
 import org.eclipse.aether.RepositorySystem;
 
+import static java.util.Collections.singletonList;
+
 /**
  * Common base class for {@link UseLatestVersionsMojo}
  * and {@link UseLatestReleasesMojo}
@@ -51,58 +59,102 @@ public abstract class UseLatestVersionsMojoBase extends AbstractVersionsDependen
         super(artifactHandlerManager, repositorySystem, wagonMap, changeRecorders);
     }
 
+    protected abstract boolean isAllowMajorUpdates();
+
+    protected abstract boolean isAllowMinorUpdates();
+
+    protected abstract boolean isAllowIncrementalUpdates();
+
+    protected abstract boolean isAllowDowngrade();
+
+    protected abstract boolean updateFilter(Dependency dep);
+
+    protected abstract boolean artifactVersionsFilter(ArtifactVersion ver);
+
+    protected abstract Optional<ArtifactVersion> versionProducer(Stream<ArtifactVersion> stream);
+
     /**
-     * Updates the pom, given a set of dependencies, a function retrieving the newest version,
-     * and an optional array of filters against which the input dependencies are matched.
-     *
-     * @param pom POM to be modified
-     * @param dependencies collection of dependencies with the dependency versions before the change
-     * @param newestVersionProducer function providing the newest version given a dependency and
-     *                              an {@link ArtifactVersions} instance
-     * @param changeKind title for the change recorder records
-     * @param filters optional array of filters
-     * @throws XMLStreamException thrown if the POM update doesn't succeed
-     * @throws MojoExecutionException if something goes wrong.
-     * @throws VersionRetrievalException thrown if an artifact versions cannot be retrieved
+     * @param pom the pom to update.
+     * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong
+     * @throws org.apache.maven.plugin.MojoFailureException   when things go wrong in a very bad way
+     * @throws javax.xml.stream.XMLStreamException            when things go wrong with XML streaming
+     * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader)
      */
-    @SafeVarargs
-    protected final void useLatestVersions(
+    protected void update(MutableXMLStreamReader pom)
+            throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException {
+        if (isAllowDowngrade() && isAllowSnapshots()) {
+            throw new MojoExecutionException("allowDowngrade is only valid with allowSnapshots equal to false");
+        }
+
+        Optional<Segment> unchangedSegment = SegmentUtils.determineUnchangedSegment(
+                isAllowMajorUpdates(), isAllowMinorUpdates(), isAllowIncrementalUpdates(), getLog());
+        try {
+            if (isProcessingDependencyManagement()) {
+                DependencyManagement dependencyManagement =
+                        PomHelper.getRawModel(getProject()).getDependencyManagement();
+                if (dependencyManagement != null) {
+                    update(
+                            pom,
+                            dependencyManagement.getDependencies(),
+                            DependencyChangeRecord.ChangeKind.DEPENDENCY_MANAGEMENT,
+                            unchangedSegment);
+                }
+            }
+            if (getProject().getDependencies() != null && isProcessingDependencies()) {
+                update(
+                        pom,
+                        getProject().getDependencies(),
+                        DependencyChangeRecord.ChangeKind.DEPENDENCY,
+                        unchangedSegment);
+            }
+            if (getProject().getParent() != null && isProcessingParent()) {
+                update(
+                        pom,
+                        singletonList(getParentDependency()),
+                        DependencyChangeRecord.ChangeKind.PARENT,
+                        unchangedSegment);
+            }
+        } catch (IOException e) {
+            throw new MojoExecutionException(e.getMessage(), e);
+        }
+    }
+
+    protected final void update(
             MutableXMLStreamReader pom,
             Collection<Dependency> dependencies,
-            BiFunction<Dependency, ArtifactVersions, Optional<ArtifactVersion>> newestVersionProducer,
             DependencyChangeRecord.ChangeKind changeKind,
-            Predicate<Dependency>... filters)
+            Optional<Segment> unchangedSegment)
             throws XMLStreamException, MojoExecutionException, VersionRetrievalException {
         for (Dependency dep : dependencies) {
-            if (!Arrays.stream(filters)
-                    .map(f -> f.test(dep))
-                    .reduce(Boolean::logicalAnd)
-                    .orElse(true)) {
+            if (!updateFilter(dep)) {
                 continue;
-            }
-
-            if (isExcludeReactor() && isProducedByReactor(dep)) {
+            } else if (isExcludeReactor() && isProducedByReactor(dep)) {
                 getLog().info("Ignoring reactor dependency: " + toString(dep));
                 continue;
-            }
-
-            if (isHandledByProperty(dep)) {
+            } else if (isHandledByProperty(dep)) {
                 getLog().debug("Ignoring dependency with property as version: " + toString(dep));
                 continue;
             }
-
             Artifact artifact = toArtifact(dep);
             if (!isIncluded(artifact)) {
                 continue;
             }
+            if (getLog().isDebugEnabled()) {
+                ArtifactVersion selectedVersion = DefaultArtifactVersionCache.of(dep.getVersion());
+                getLog().debug("Selected version:" + selectedVersion);
+                getLog().debug("Looking for newer versions of " + toString(dep));
+            }
 
-            ArtifactVersion selectedVersion = DefaultArtifactVersionCache.of(dep.getVersion());
-            getLog().debug("Selected version:" + selectedVersion);
-            getLog().debug("Looking for newer versions of " + toString(dep));
             ArtifactVersions versions = getHelper().lookupArtifactVersions(artifact, false);
-            Optional<ArtifactVersion> newestVer = newestVersionProducer.apply(dep, versions);
-            if (newestVer.isPresent()) {
-                updateDependencyVersion(pom, dep, newestVer.get().toString(), changeKind);
+            try {
+                Optional<ArtifactVersion> newestVer = versionProducer(Arrays.stream(versions.getNewerVersions(
+                                dep.getVersion(), unchangedSegment, isAllowSnapshots(), isAllowDowngrade()))
+                        .filter(this::artifactVersionsFilter));
+                if (newestVer.isPresent()) {
+                    updateDependencyVersion(pom, dep, newestVer.get().toString(), changeKind);
+                }
+            } catch (InvalidSegmentException e) {
+                getLog().warn("Ignoring " + this.toString(dep) + " as the version number is too short");
             }
         }
     }
diff --git a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SeparatePatternsForIncludesAnExcludesTest.java b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SeparatePatternsForIncludesAnExcludesTest.java
index 1d7c0d9c..e3aaa628 100644
--- a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SeparatePatternsForIncludesAnExcludesTest.java
+++ b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SeparatePatternsForIncludesAnExcludesTest.java
@@ -15,6 +15,11 @@ public class SeparatePatternsForIncludesAnExcludesTest {
     @Before
     public void setUp() throws Exception {
         mojo = new AbstractVersionsDependencyUpdaterMojo(null, null, null, null) {
+            @Override
+            protected boolean isAllowSnapshots() {
+                return false;
+            }
+
             @Override
             protected void update(MutableXMLStreamReader pom) {}
         };
diff --git a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestReleasesMojoTest.java b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestReleasesMojoTest.java
index 2c2301eb..a58453d0 100644
--- a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestReleasesMojoTest.java
+++ b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestReleasesMojoTest.java
@@ -19,21 +19,16 @@ import javax.xml.stream.XMLStreamException;
 
 import java.util.HashMap;
 
-import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
 import org.apache.maven.model.Model;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.mojo.versions.api.PomHelper;
 import org.codehaus.mojo.versions.api.VersionRetrievalException;
 import org.codehaus.mojo.versions.change.DefaultDependencyVersionChange;
 import org.codehaus.mojo.versions.utils.DependencyBuilder;
-import org.codehaus.mojo.versions.utils.TestChangeRecorder;
-import org.eclipse.aether.RepositorySystem;
 import org.hamcrest.Matchers;
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.MockedStatic;
 
 import static java.util.Collections.emptyList;
 import static java.util.Collections.singletonList;
@@ -45,53 +40,42 @@ import static org.codehaus.mojo.versions.utils.MockUtils.mockMavenSession;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.hasItem;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mockStatic;
 
-public class UseLatestReleasesMojoTest {
-    private UseLatestReleasesMojo mojo;
-    private TestChangeRecorder changeRecorder;
+public class UseLatestReleasesMojoTest extends UseLatestVersionsMojoTestBase {
 
     @Before
     public void setUp() throws Exception {
-        ArtifactHandlerManager artifactHandlerManager = mockArtifactHandlerManager();
-        RepositorySystem repositorySystem = mockAetherRepositorySystem(new HashMap<String, String[]>() {
-            {
-                put("dependency-artifact", new String[] {"0.9.0", "1.0.0-beta"});
-            }
-        });
-
-        changeRecorder = new TestChangeRecorder();
-
-        mojo = new UseLatestReleasesMojo(artifactHandlerManager, repositorySystem, null, changeRecorder.asTestMap()) {
-            {
-                reactorProjects = emptyList();
-                MavenProject project = new MavenProject() {
+        changeRecorder = createChangeRecorder();
+        mojo =
+                new UseLatestReleasesMojo(
+                        mockArtifactHandlerManager(), createRepositorySystem(), null, changeRecorder.asTestMap()) {
                     {
-                        setModel(new Model() {
+                        reactorProjects = emptyList();
+                        MavenProject project = new MavenProject() {
                             {
-                                setGroupId("default-group");
-                                setArtifactId("project-artifact");
-                                setVersion("1.0.0-SNAPSHOT");
-
-                                setDependencies(singletonList(DependencyBuilder.newBuilder()
-                                        .withGroupId("default-group")
-                                        .withArtifactId("dependency-artifact")
-                                        .withVersion("0.9.0")
-                                        .withScope(SCOPE_COMPILE)
-                                        .withType("jar")
-                                        .withClassifier("default")
-                                        .build()));
+                                setModel(new Model() {
+                                    {
+                                        setGroupId("default-group");
+                                        setArtifactId("project-artifact");
+                                        setVersion("1.0.0-SNAPSHOT");
+
+                                        setDependencies(singletonList(DependencyBuilder.newBuilder()
+                                                .withGroupId("default-group")
+                                                .withArtifactId("dependency-artifact")
+                                                .withVersion("0.9.0")
+                                                .withScope(SCOPE_COMPILE)
+                                                .withType("jar")
+                                                .withClassifier("default")
+                                                .build()));
+                                    }
+                                });
                             }
-                        });
+                        };
+                        setProject(project);
+
+                        session = mockMavenSession();
                     }
                 };
-                setProject(project);
-
-                session = mockMavenSession();
-            }
-        };
     }
 
     @Test
@@ -99,26 +83,18 @@ public class UseLatestReleasesMojoTest {
             throws MojoExecutionException, XMLStreamException, MojoFailureException, IllegalAccessException,
                     VersionRetrievalException {
         setVariableValueToObject(mojo, "processDependencies", true);
-        setVariableValueToObject(mojo, "allowSnapshots", false);
         setVariableValueToObject(mojo, "allowMajorUpdates", false);
         setVariableValueToObject(mojo, "allowMinorUpdates", true);
         setVariableValueToObject(mojo, "allowIncrementalUpdates", false);
 
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any(), any()))
-                    .thenReturn(true);
-            pomHelper
-                    .when(() -> PomHelper.getRawModel(any(MavenProject.class)))
-                    .thenReturn(mojo.getProject().getModel());
-            mojo.update(null);
-        }
+        tryUpdate();
         assertThat(changeRecorder.getChanges(), Matchers.empty());
     }
 
     @Test
     public void testAllowDowngrade()
-            throws MojoExecutionException, XMLStreamException, MojoFailureException, VersionRetrievalException {
+            throws MojoExecutionException, XMLStreamException, MojoFailureException, VersionRetrievalException,
+                    IllegalAccessException {
         mojo.repositorySystem = mockAetherRepositorySystem(new HashMap<String, String[]>() {
             {
                 put("artifactA", new String[] {"1.0.0", "1.0.1-SNAPSHOT"});
@@ -130,18 +106,9 @@ public class UseLatestReleasesMojoTest {
                         .withArtifactId("artifactA")
                         .withVersion("1.0.1-SNAPSHOT")
                         .build()));
-        mojo.allowDowngrade = true;
+        setVariableValueToObject(mojo, "allowDowngrade", true);
 
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(
-                            any(), anyString(), anyString(), anyString(), anyString(), any(Model.class), any()))
-                    .thenReturn(true);
-            pomHelper
-                    .when(() -> PomHelper.getRawModel(any(MavenProject.class)))
-                    .thenReturn(mojo.getProject().getModel());
-            mojo.update(null);
-        }
+        tryUpdate();
         assertThat(
                 changeRecorder.getChanges(),
                 hasItem(new DefaultDependencyVersionChange(
@@ -164,16 +131,7 @@ public class UseLatestReleasesMojoTest {
                         .withVersion("1.0.1-SNAPSHOT")
                         .build()));
 
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(
-                            any(), anyString(), anyString(), anyString(), anyString(), any(Model.class), any()))
-                    .thenReturn(true);
-            pomHelper
-                    .when(() -> PomHelper.getRawModel(any(MavenProject.class)))
-                    .thenReturn(mojo.getProject().getModel());
-            mojo.update(null);
-        }
+        tryUpdate();
         assertThat(changeRecorder.getChanges(), empty());
     }
 }
diff --git a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestSnapshotsMojoTest.java b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestSnapshotsMojoTest.java
new file mode 100644
index 00000000..9e84b122
--- /dev/null
+++ b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestSnapshotsMojoTest.java
@@ -0,0 +1,74 @@
+package org.codehaus.mojo.versions;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.mojo.versions.api.VersionRetrievalException;
+import org.codehaus.mojo.versions.utils.DependencyBuilder;
+import org.junit.Before;
+import org.junit.Test;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static org.apache.maven.artifact.Artifact.SCOPE_COMPILE;
+import static org.codehaus.mojo.versions.utils.MockUtils.mockArtifactHandlerManager;
+import static org.codehaus.mojo.versions.utils.MockUtils.mockMavenSession;
+
+public class UseLatestSnapshotsMojoTest extends UseLatestVersionsMojoTestBase {
+    @Before
+    public void setUp() throws Exception {
+        changeRecorder = createChangeRecorder();
+        mojo =
+                new UseLatestSnapshotsMojo(
+                        mockArtifactHandlerManager(), createRepositorySystem(), null, changeRecorder.asTestMap()) {
+                    {
+                        reactorProjects = emptyList();
+                        MavenProject project = new MavenProject() {
+                            {
+                                setModel(new Model() {
+                                    {
+                                        setGroupId("default-group");
+                                        setArtifactId("project-artifact");
+                                        setVersion("1.0.0-SNAPSHOT");
+
+                                        setDependencies(singletonList(DependencyBuilder.newBuilder()
+                                                .withGroupId("default-group")
+                                                .withArtifactId("dependency-artifact")
+                                                .withVersion("0.9.0")
+                                                .withScope(SCOPE_COMPILE)
+                                                .withType("jar")
+                                                .withClassifier("default")
+                                                .build()));
+                                    }
+                                });
+                            }
+                        };
+                        setProject(project);
+
+                        session = mockMavenSession();
+                        allowMajorUpdates = true;
+                        allowMinorUpdates = true;
+                        allowIncrementalUpdates = true;
+                    }
+                };
+    }
+
+    @Test
+    @Override
+    public void testIncludeFilter()
+            throws MojoExecutionException, XMLStreamException, MojoFailureException, IllegalAccessException,
+                    VersionRetrievalException {
+        testIncludeFilter("2.0-SNAPSHOT");
+    }
+
+    @Test
+    @Override
+    public void testExcludeFilter()
+            throws MojoExecutionException, XMLStreamException, MojoFailureException, IllegalAccessException,
+                    VersionRetrievalException {
+        testExcludeFilter("2.0-SNAPSHOT");
+    }
+}
diff --git a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestVersionsMojoTest.java b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestVersionsMojoTest.java
index 8494a808..8e30e208 100644
--- a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestVersionsMojoTest.java
+++ b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestVersionsMojoTest.java
@@ -19,7 +19,6 @@ import javax.xml.stream.XMLStreamException;
 
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
 
 import org.apache.maven.artifact.DefaultArtifact;
 import org.apache.maven.model.DependencyManagement;
@@ -27,55 +26,28 @@ import org.apache.maven.model.Model;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.mojo.versions.api.PomHelper;
 import org.codehaus.mojo.versions.api.VersionRetrievalException;
 import org.codehaus.mojo.versions.change.DefaultDependencyVersionChange;
 import org.codehaus.mojo.versions.utils.DependencyBuilder;
-import org.codehaus.mojo.versions.utils.TestChangeRecorder;
-import org.eclipse.aether.RepositorySystem;
-import org.hamcrest.core.Is;
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.MockedStatic;
 
 import static java.util.Collections.emptyList;
-import static java.util.Collections.singleton;
 import static org.apache.maven.artifact.Artifact.SCOPE_COMPILE;
 import static org.apache.maven.plugin.testing.ArtifactStubFactory.setVariableValueToObject;
-import static org.codehaus.mojo.versions.utils.MockUtils.mockAetherRepositorySystem;
 import static org.codehaus.mojo.versions.utils.MockUtils.mockArtifactHandlerManager;
 import static org.codehaus.mojo.versions.utils.MockUtils.mockMavenSession;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.hasItem;
-import static org.hamcrest.Matchers.hasSize;
-import static org.hamcrest.Matchers.not;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mockStatic;
 
-public class UseLatestVersionsMojoTest {
-    private UseLatestVersionsMojo mojo;
-    private TestChangeRecorder changeRecorder;
+public class UseLatestVersionsMojoTest extends UseLatestVersionsMojoTestBase {
 
     @Before
     public void setUp() throws Exception {
-        RepositorySystem repositorySystem = mockAetherRepositorySystem(new HashMap<String, String[]>() {
-            {
-                put(
-                        "dependency-artifact",
-                        new String[] {"1.1.1-SNAPSHOT", "1.1.0", "1.1.0-SNAPSHOT", "1.0.0", "1.0.0-SNAPSHOT", "0.9.0"});
-                put("poison-artifact", new String[] {
-                    "1.1.1.1-SNAPSHOT", "1.1.1.0", "1.1.1.0-SNAPSHOT", "1.0.0.0", "1.0.0.0-SNAPSHOT", "0.9.0.0"
-                });
-                put("other-artifact", new String[] {"1.0", "2.0"});
-            }
-        });
-
-        changeRecorder = new TestChangeRecorder();
-
+        changeRecorder = createChangeRecorder();
         mojo =
                 new UseLatestVersionsMojo(
-                        mockArtifactHandlerManager(), repositorySystem, null, changeRecorder.asTestMap()) {
+                        mockArtifactHandlerManager(), createRepositorySystem(), null, changeRecorder.asTestMap()) {
                     {
                         reactorProjects = emptyList();
                         MavenProject project = new MavenProject() {
@@ -129,12 +101,7 @@ public class UseLatestVersionsMojoTest {
         setVariableValueToObject(mojo, "allowIncrementalUpdates", true);
         setVariableValueToObject(mojo, "allowDowngrade", true);
 
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any(), any()))
-                    .thenReturn(true);
-            mojo.update(null);
-        }
+        tryUpdate();
         assertThat(
                 changeRecorder.getChanges(),
                 hasItem(new DefaultDependencyVersionChange(
@@ -163,12 +130,7 @@ public class UseLatestVersionsMojoTest {
                         .withScope(SCOPE_COMPILE)
                         .build()));
 
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any(), any()))
-                    .thenReturn(true);
-            mojo.update(null);
-        }
+        tryUpdate();
         assertThat(
                 changeRecorder.getChanges(),
                 hasItem(new DefaultDependencyVersionChange(
@@ -187,12 +149,7 @@ public class UseLatestVersionsMojoTest {
         setVariableValueToObject(mojo, "allowIncrementalUpdates", true);
         setVariableValueToObject(mojo, "allowDowngrade", true);
 
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any(), any()))
-                    .thenReturn(true);
-            mojo.update(null);
-        }
+        tryUpdate();
         assertThat(
                 changeRecorder.getChanges(),
                 hasItem(new DefaultDependencyVersionChange(
@@ -211,15 +168,7 @@ public class UseLatestVersionsMojoTest {
         setVariableValueToObject(mojo, "allowIncrementalUpdates", true);
         setVariableValueToObject(mojo, "allowDowngrade", true);
 
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.getRawModel(any(MavenProject.class)))
-                    .thenReturn(mojo.getProject().getModel());
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any(), any()))
-                    .thenReturn(true);
-            mojo.update(null);
-        }
+        tryUpdate();
         assertThat(
                 changeRecorder.getChanges(),
                 hasItem(new DefaultDependencyVersionChange(
@@ -248,12 +197,7 @@ public class UseLatestVersionsMojoTest {
             }
         });
 
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any(), any()))
-                    .thenReturn(true);
-            mojo.update(null);
-        }
+        tryUpdate();
         assertThat(
                 changeRecorder.getChanges(),
                 hasItem(new DefaultDependencyVersionChange(
@@ -291,12 +235,7 @@ public class UseLatestVersionsMojoTest {
         setVariableValueToObject(mojo, "allowIncrementalUpdates", true);
         setVariableValueToObject(mojo, "allowDowngrade", true);
 
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any(), any()))
-                    .thenReturn(true);
-            mojo.update(null);
-        }
+        tryUpdate();
         // So, the regular update should take place despite an irregular, or — if I may — "poison", dependency
         // being present in the dependency list
         assertThat(
@@ -304,96 +243,4 @@ public class UseLatestVersionsMojoTest {
                 hasItem(new DefaultDependencyVersionChange(
                         "default-group", "dependency-artifact", "1.1.1-SNAPSHOT", "1.1.0")));
     }
-
-    @Test
-    public void testIgnoredVersions()
-            throws MojoExecutionException, XMLStreamException, MojoFailureException, IllegalAccessException,
-                    VersionRetrievalException {
-        setVariableValueToObject(mojo, "processDependencies", true);
-        setVariableValueToObject(mojo, "ignoredVersions", singleton("1.1.0"));
-
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any(), any()))
-                    .thenReturn(true);
-            mojo.update(null);
-        }
-        assertThat(changeRecorder.getChanges(), Is.is(empty()));
-    }
-
-    @Test
-    public void testIncludeFilter()
-            throws MojoExecutionException, XMLStreamException, MojoFailureException, IllegalAccessException,
-                    VersionRetrievalException {
-        mojo.getProject()
-                .getModel()
-                .setDependencies(Arrays.asList(
-                        DependencyBuilder.newBuilder()
-                                .withGroupId("default-group")
-                                .withArtifactId("dependency-artifact")
-                                .withVersion("0.9.0")
-                                .withType("pom")
-                                .withClassifier("default")
-                                .withScope(SCOPE_COMPILE)
-                                .build(),
-                        DependencyBuilder.newBuilder()
-                                .withGroupId("default-group")
-                                .withArtifactId("other-artifact")
-                                .withVersion("1.0")
-                                .withType("pom")
-                                .withClassifier("default")
-                                .withScope(SCOPE_COMPILE)
-                                .build()));
-        setVariableValueToObject(mojo, "processDependencies", true);
-        setVariableValueToObject(mojo, "includes", new String[] {"default-group:other-artifact"});
-
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any(), any()))
-                    .thenReturn(true);
-            mojo.update(null);
-        }
-        assertThat(changeRecorder.getChanges(), hasSize(1));
-        assertThat(
-                changeRecorder.getChanges(),
-                hasItem(new DefaultDependencyVersionChange("default-group", "other-artifact", "1.0", "2.0")));
-    }
-
-    @Test
-    public void testExcludeFilter()
-            throws MojoExecutionException, XMLStreamException, MojoFailureException, IllegalAccessException,
-                    VersionRetrievalException {
-        mojo.getProject()
-                .getModel()
-                .setDependencies(Arrays.asList(
-                        DependencyBuilder.newBuilder()
-                                .withGroupId("default-group")
-                                .withArtifactId("dependency-artifact")
-                                .withVersion("0.9.0")
-                                .withType("pom")
-                                .withClassifier("default")
-                                .withScope(SCOPE_COMPILE)
-                                .build(),
-                        DependencyBuilder.newBuilder()
-                                .withGroupId("default-group")
-                                .withArtifactId("other-artifact")
-                                .withVersion("1.0")
-                                .withType("pom")
-                                .withClassifier("default")
-                                .withScope(SCOPE_COMPILE)
-                                .build()));
-        setVariableValueToObject(mojo, "processDependencies", true);
-        setVariableValueToObject(mojo, "excludes", new String[] {"default-group:other-artifact"});
-
-        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
-            pomHelper
-                    .when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any(), any()))
-                    .thenReturn(true);
-            mojo.update(null);
-        }
-        assertThat(changeRecorder.getChanges(), hasSize(1));
-        assertThat(
-                changeRecorder.getChanges(),
-                not(hasItem(new DefaultDependencyVersionChange("default-group", "other-artifact", "1.0", "2.0"))));
-    }
 }
diff --git a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestVersionsMojoTestBase.java b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestVersionsMojoTestBase.java
new file mode 100644
index 00000000..33e4530b
--- /dev/null
+++ b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UseLatestVersionsMojoTestBase.java
@@ -0,0 +1,168 @@
+package org.codehaus.mojo.versions;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.mojo.versions.api.PomHelper;
+import org.codehaus.mojo.versions.api.VersionRetrievalException;
+import org.codehaus.mojo.versions.change.DefaultDependencyVersionChange;
+import org.codehaus.mojo.versions.utils.DependencyBuilder;
+import org.codehaus.mojo.versions.utils.TestChangeRecorder;
+import org.eclipse.aether.RepositorySystem;
+import org.hamcrest.core.Is;
+import org.junit.Test;
+import org.mockito.MockedStatic;
+
+import static org.apache.maven.artifact.Artifact.SCOPE_COMPILE;
+import static org.apache.maven.plugin.testing.ArtifactStubFactory.setVariableValueToObject;
+import static org.codehaus.mojo.versions.utils.MockUtils.mockAetherRepositorySystem;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.not;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mockStatic;
+
+public abstract class UseLatestVersionsMojoTestBase {
+    protected UseLatestVersionsMojoBase mojo;
+
+    protected TestChangeRecorder changeRecorder;
+
+    protected RepositorySystem createRepositorySystem() {
+        return mockAetherRepositorySystem(new HashMap<String, String[]>() {
+            {
+                put("dependency-artifact", new String[] {
+                    "1.1.1-SNAPSHOT", "1.1.0", "1.1.0-SNAPSHOT", "1.0.0", "1.0.0-beta", "1.0.0-SNAPSHOT", "0.9.0"
+                });
+                put("poison-artifact", new String[] {
+                    "1.1.1.1-SNAPSHOT", "1.1.1.0", "1.1.1.0-SNAPSHOT", "1.0.0.0", "1.0.0.0-SNAPSHOT", "0.9.0.0"
+                });
+                put("other-artifact", new String[] {"1.0", "2.0", "2.0-SNAPSHOT"});
+            }
+        });
+    }
+
+    protected TestChangeRecorder createChangeRecorder() {
+        return new TestChangeRecorder();
+    }
+
+    protected void tryUpdate()
+            throws MojoExecutionException, XMLStreamException, MojoFailureException, VersionRetrievalException {
+        try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
+            pomHelper
+                    .when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any(), any()))
+                    .thenReturn(true);
+            pomHelper
+                    .when(() -> PomHelper.getRawModel(any(MavenProject.class)))
+                    .thenReturn(mojo.getProject().getModel());
+            mojo.update(null);
+        }
+    }
+
+    @Test
+    public void testIgnoredVersions()
+            throws MojoExecutionException, XMLStreamException, MojoFailureException, IllegalAccessException,
+                    VersionRetrievalException {
+        setVariableValueToObject(mojo, "processDependencies", true);
+        setVariableValueToObject(mojo, "ignoredVersions", new HashSet<String>() {
+            {
+                add("1.0.0");
+                add("1.0.0-beta");
+                add("1.1.0");
+                add("1.0.0-SNAPSHOT");
+                add("1.1.0-SNAPSHOT");
+                add("1.1.1-SNAPSHOT");
+            }
+        });
+
+        tryUpdate();
+        assertThat(changeRecorder.getChanges(), Is.is(empty()));
+    }
+
+    protected void testIncludeFilter(String expectedNewVersion)
+            throws MojoExecutionException, XMLStreamException, MojoFailureException, IllegalAccessException,
+                    VersionRetrievalException {
+        mojo.getProject()
+                .getModel()
+                .setDependencies(Arrays.asList(
+                        DependencyBuilder.newBuilder()
+                                .withGroupId("default-group")
+                                .withArtifactId("dependency-artifact")
+                                .withVersion("0.9.0")
+                                .withType("pom")
+                                .withClassifier("default")
+                                .withScope(SCOPE_COMPILE)
+                                .build(),
+                        DependencyBuilder.newBuilder()
+                                .withGroupId("default-group")
+                                .withArtifactId("other-artifact")
+                                .withVersion("1.0")
+                                .withType("pom")
+                                .withClassifier("default")
+                                .withScope(SCOPE_COMPILE)
+                                .build()));
+        setVariableValueToObject(mojo, "processDependencies", true);
+        setVariableValueToObject(mojo, "includes", new String[] {"default-group:other-artifact"});
+
+        tryUpdate();
+        assertThat(changeRecorder.getChanges(), hasSize(1));
+        assertThat(
+                changeRecorder.getChanges(),
+                hasItem(new DefaultDependencyVersionChange(
+                        "default-group", "other-artifact", "1.0", expectedNewVersion)));
+    }
+
+    @Test
+    public void testIncludeFilter()
+            throws MojoExecutionException, XMLStreamException, MojoFailureException, IllegalAccessException,
+                    VersionRetrievalException {
+        testIncludeFilter("2.0");
+    }
+
+    protected void testExcludeFilter(String expectedNewVersion)
+            throws IllegalAccessException, MojoExecutionException, XMLStreamException, MojoFailureException,
+                    VersionRetrievalException {
+        mojo.getProject()
+                .getModel()
+                .setDependencies(Arrays.asList(
+                        DependencyBuilder.newBuilder()
+                                .withGroupId("default-group")
+                                .withArtifactId("dependency-artifact")
+                                .withVersion("0.9.0")
+                                .withType("pom")
+                                .withClassifier("default")
+                                .withScope(SCOPE_COMPILE)
+                                .build(),
+                        DependencyBuilder.newBuilder()
+                                .withGroupId("default-group")
+                                .withArtifactId("other-artifact")
+                                .withVersion("1.0")
+                                .withType("pom")
+                                .withClassifier("default")
+                                .withScope(SCOPE_COMPILE)
+                                .build()));
+        setVariableValueToObject(mojo, "processDependencies", true);
+        setVariableValueToObject(mojo, "excludes", new String[] {"default-group:other-artifact"});
+
+        tryUpdate();
+        assertThat(changeRecorder.getChanges(), hasSize(1));
+        assertThat(
+                changeRecorder.getChanges(),
+                not(hasItem(new DefaultDependencyVersionChange(
+                        "default-group", "other-artifact", "1.0", expectedNewVersion))));
+    }
+
+    @Test
+    public void testExcludeFilter()
+            throws MojoExecutionException, XMLStreamException, MojoFailureException, IllegalAccessException,
+                    VersionRetrievalException {
+        testExcludeFilter("2.0");
+    }
+}