aliases() {
static class SiteLifecycle implements Lifecycle {
- private static final String MAVEN_SITE_PLUGIN_VERSION = "3.21.0";
+ private static final String MAVEN_SITE_PLUGIN_VERSION = PluginVersions.SITE;
private static final String MAVEN_SITE_PLUGIN =
MAVEN_PLUGINS + "maven-site-plugin:" + MAVEN_SITE_PLUGIN_VERSION + ":";
private static final String PHASE_SITE = "site";
diff --git a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/PluginVersions.java b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/PluginVersions.java
new file mode 100644
index 000000000000..0a1e4a7ee9be
--- /dev/null
+++ b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/PluginVersions.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.lifecycle;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * Provides default plugin versions for the built-in lifecycle bindings.
+ *
+ * Versions are read from {@code plugin-versions.properties}, which is filtered
+ * at build time from POM properties ({@code version.maven--plugin}).
+ * Centralising them in the POM makes them visible to dependency-update bots
+ * such as Dependabot and Renovate.
+ *
+ * @since 4.1.0
+ */
+public final class PluginVersions {
+
+ private static final Properties VERSIONS = new Properties();
+
+ static {
+ try (InputStream in = PluginVersions.class.getResourceAsStream("plugin-versions.properties")) {
+ if (in == null) {
+ throw new ExceptionInInitializerError("plugin-versions.properties not found on classpath");
+ }
+ VERSIONS.load(in);
+ } catch (IOException e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ private PluginVersions() {}
+
+ private static String version(String pluginArtifactId) {
+ String key = "version." + pluginArtifactId;
+ String version = VERSIONS.getProperty(key);
+ if (version == null) {
+ throw new IllegalArgumentException("No default version defined for " + pluginArtifactId + "; add " + key
+ + " to plugin-versions.properties");
+ }
+ if (version.startsWith("${")) {
+ throw new ExceptionInInitializerError("plugin-versions.properties was not filtered at build time; " + key
+ + " still contains placeholder: " + version);
+ }
+ return version;
+ }
+
+ // --- convenience constants used by lifecycle mapping providers ---
+
+ public static final String CLEAN = version("maven-clean-plugin");
+ public static final String COMPILER = version("maven-compiler-plugin");
+ public static final String DEPLOY = version("maven-deploy-plugin");
+ public static final String EAR = version("maven-ear-plugin");
+ public static final String EJB = version("maven-ejb-plugin");
+ public static final String INSTALL = version("maven-install-plugin");
+ public static final String JAR = version("maven-jar-plugin");
+ public static final String PLUGIN = version("maven-plugin-plugin");
+ public static final String RAR = version("maven-rar-plugin");
+ public static final String RESOURCES = version("maven-resources-plugin");
+ public static final String SITE = version("maven-site-plugin");
+ public static final String SUREFIRE = version("maven-surefire-plugin");
+ public static final String WAR = version("maven-war-plugin");
+}
diff --git a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java
index ed841bcccdd9..3802905b4331 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java
@@ -23,6 +23,7 @@
import java.util.Collections;
import java.util.HashMap;
+import org.apache.maven.lifecycle.PluginVersions;
import org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping;
import org.apache.maven.lifecycle.mapping.Lifecycle;
import org.apache.maven.lifecycle.mapping.LifecycleMapping;
@@ -35,29 +36,51 @@
*/
public abstract class AbstractLifecycleMappingProvider implements Provider {
// START SNIPPET: versions
- protected static final String RESOURCES_PLUGIN_VERSION = "3.3.1";
+ /** @deprecated Use {@link PluginVersions#RESOURCES} instead. */
+ @Deprecated(since = "4.1.0", forRemoval = true)
+ protected static final String RESOURCES_PLUGIN_VERSION = PluginVersions.RESOURCES;
- protected static final String COMPILER_PLUGIN_VERSION = "3.13.0";
+ /** @deprecated Use {@link PluginVersions#COMPILER} instead. */
+ @Deprecated(since = "4.1.0", forRemoval = true)
+ protected static final String COMPILER_PLUGIN_VERSION = PluginVersions.COMPILER;
- protected static final String SUREFIRE_PLUGIN_VERSION = "3.5.2";
+ /** @deprecated Use {@link PluginVersions#SUREFIRE} instead. */
+ @Deprecated(since = "4.1.0", forRemoval = true)
+ protected static final String SUREFIRE_PLUGIN_VERSION = PluginVersions.SUREFIRE;
- protected static final String INSTALL_PLUGIN_VERSION = "3.1.3";
+ /** @deprecated Use {@link PluginVersions#INSTALL} instead. */
+ @Deprecated(since = "4.1.0", forRemoval = true)
+ protected static final String INSTALL_PLUGIN_VERSION = PluginVersions.INSTALL;
- protected static final String DEPLOY_PLUGIN_VERSION = "3.1.3";
+ /** @deprecated Use {@link PluginVersions#DEPLOY} instead. */
+ @Deprecated(since = "4.1.0", forRemoval = true)
+ protected static final String DEPLOY_PLUGIN_VERSION = PluginVersions.DEPLOY;
// packaging
- protected static final String JAR_PLUGIN_VERSION = "3.4.2";
+ /** @deprecated Use {@link PluginVersions#JAR} instead. */
+ @Deprecated(since = "4.1.0", forRemoval = true)
+ protected static final String JAR_PLUGIN_VERSION = PluginVersions.JAR;
- protected static final String EAR_PLUGIN_VERSION = "3.3.0";
+ /** @deprecated Use {@link PluginVersions#EAR} instead. */
+ @Deprecated(since = "4.1.0", forRemoval = true)
+ protected static final String EAR_PLUGIN_VERSION = PluginVersions.EAR;
- protected static final String EJB_PLUGIN_VERSION = "3.2.1";
+ /** @deprecated Use {@link PluginVersions#EJB} instead. */
+ @Deprecated(since = "4.1.0", forRemoval = true)
+ protected static final String EJB_PLUGIN_VERSION = PluginVersions.EJB;
- protected static final String PLUGIN_PLUGIN_VERSION = "3.15.1";
+ /** @deprecated Use {@link PluginVersions#PLUGIN} instead. */
+ @Deprecated(since = "4.1.0", forRemoval = true)
+ protected static final String PLUGIN_PLUGIN_VERSION = PluginVersions.PLUGIN;
- protected static final String RAR_PLUGIN_VERSION = "3.0.0";
+ /** @deprecated Use {@link PluginVersions#RAR} instead. */
+ @Deprecated(since = "4.1.0", forRemoval = true)
+ protected static final String RAR_PLUGIN_VERSION = PluginVersions.RAR;
- protected static final String WAR_PLUGIN_VERSION = "3.4.0";
+ /** @deprecated Use {@link PluginVersions#WAR} instead. */
+ @Deprecated(since = "4.1.0", forRemoval = true)
+ protected static final String WAR_PLUGIN_VERSION = PluginVersions.WAR;
// END SNIPPET: versions
private final LifecycleMapping lifecycleMapping;
diff --git a/impl/maven-core/src/main/resources/org/apache/maven/lifecycle/plugin-versions.properties b/impl/maven-core/src/main/resources/org/apache/maven/lifecycle/plugin-versions.properties
new file mode 100644
index 000000000000..701d8a30fc43
--- /dev/null
+++ b/impl/maven-core/src/main/resources/org/apache/maven/lifecycle/plugin-versions.properties
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Default lifecycle plugin versions.
+# Values are substituted by Maven resource filtering at build time from
+# POM properties (version.maven--plugin), making them visible to
+# dependency-update bots such as Dependabot and Renovate.
+
+version.maven-clean-plugin=${version.maven-clean-plugin}
+version.maven-compiler-plugin=${version.maven-compiler-plugin}
+version.maven-deploy-plugin=${version.maven-deploy-plugin}
+version.maven-ear-plugin=${version.maven-ear-plugin}
+version.maven-ejb-plugin=${version.maven-ejb-plugin}
+version.maven-install-plugin=${version.maven-install-plugin}
+version.maven-jar-plugin=${version.maven-jar-plugin}
+version.maven-plugin-plugin=${version.maven-plugin-plugin}
+version.maven-rar-plugin=${version.maven-rar-plugin}
+version.maven-resources-plugin=${version.maven-resources-plugin}
+version.maven-site-plugin=${version.maven-site-plugin}
+version.maven-surefire-plugin=${version.maven-surefire-plugin}
+version.maven-war-plugin=${version.maven-war-plugin}
diff --git a/impl/maven-core/src/test/java/org/apache/maven/lifecycle/PluginVersionsTest.java b/impl/maven-core/src/test/java/org/apache/maven/lifecycle/PluginVersionsTest.java
new file mode 100644
index 000000000000..0f28b9029789
--- /dev/null
+++ b/impl/maven-core/src/test/java/org/apache/maven/lifecycle/PluginVersionsTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.lifecycle;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Verifies that {@link PluginVersions} constants are properly loaded
+ * from the filtered {@code plugin-versions.properties} resource.
+ */
+class PluginVersionsTest {
+
+ @Test
+ void allConstantsAreResolvedAndNotPlaceholders() throws Exception {
+ int count = 0;
+ for (Field field : PluginVersions.class.getFields()) {
+ if (field.getType() == String.class
+ && Modifier.isStatic(field.getModifiers())
+ && Modifier.isFinal(field.getModifiers())) {
+ String value = (String) field.get(null);
+ assertNotNull(value, field.getName() + " is null");
+ assertFalse(value.startsWith("${"), field.getName() + " contains unfiltered placeholder: " + value);
+ assertFalse(value.isEmpty(), field.getName() + " is empty");
+ count++;
+ }
+ }
+ // Ensure we actually tested something — catches the case where
+ // all constants are accidentally removed or made non-public.
+ assertTrue(count >= 13, "Expected at least 13 plugin version constants, found " + count);
+ }
+}