This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch maven-3.9.x
in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/maven-3.9.x by this push:
new e7691912d8 [MNG-8707] Add methods to remove compile and test source
roots (#2275)
e7691912d8 is described below
commit e7691912d8b1296f961eb7db862c50d296fe8e98
Author: Guillaume Nodet <[email protected]>
AuthorDate: Wed Apr 30 23:10:07 2025 +0200
[MNG-8707] Add methods to remove compile and test source roots (#2275)
---
.../org/apache/maven/project/MavenProject.java | 290 +++++++++++++++++++--
1 file changed, 271 insertions(+), 19 deletions(-)
diff --git
a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
index 97d595291e..29a18ff0b2 100644
--- a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
+++ b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
@@ -21,12 +21,16 @@
import java.io.File;
import java.io.IOException;
import java.io.Writer;
+import java.util.AbstractList;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
@@ -276,40 +280,104 @@ public DependencyManagement getDependencyManagement() {
// Test and compile sourceroots.
// ----------------------------------------------------------------------
+ /**
+ * Sanitizes a path by trimming it and converting it to an absolute path.
+ *
+ * @param path the path to sanitize
+ * @return the sanitized path, or null if the input path is null, empty,
or consists only of whitespace
+ */
+ private String sanitizePath(String path) {
+ if (path == null) {
+ return null;
+ }
+ path = path.trim();
+ if (path.isEmpty()) {
+ return null;
+ }
+ File file = new File(path);
+ if (file.isAbsolute()) {
+ return file.getAbsolutePath();
+ } else if (".".equals(path)) {
+ return getBasedir().getAbsolutePath();
+ } else {
+ return new File(getBasedir(), path).getAbsolutePath();
+ }
+ }
+
private void addPath(List<String> paths, String path) {
- if (path != null) {
- path = path.trim();
- if (path.length() > 0) {
- File file = new File(path);
- if (file.isAbsolute()) {
- path = file.getAbsolutePath();
- } else if (".".equals(path)) {
- path = getBasedir().getAbsolutePath();
- } else {
- path = new File(getBasedir(), path).getAbsolutePath();
- }
+ String sanitizedPath = sanitizePath(path);
+ if (sanitizedPath != null && !paths.contains(sanitizedPath)) {
+ paths.add(sanitizedPath);
+ }
+ }
- if (!paths.contains(path)) {
- paths.add(path);
- }
- }
+ private void removePath(List<String> paths, String path) {
+ String sanitizedPath = sanitizePath(path);
+ if (sanitizedPath != null) {
+ paths.remove(sanitizedPath);
}
}
+ /**
+ * Adds the specified path to the list of compile source roots for this
project.
+ *
+ * @param path the source root to add
+ */
public void addCompileSourceRoot(String path) {
- addPath(getCompileSourceRoots(), path);
+ addPath(compileSourceRoots, path);
}
+ /**
+ * Removes the specified path from the list of compile source roots.
+ *
+ * @param path the source root to remove
+ * @since 3.9.10
+ */
+ public void removeCompileSourceRoot(String path) {
+ removePath(compileSourceRoots, path);
+ }
+
+ /**
+ * Adds the specified path to the list of test compile source roots for
this project.
+ *
+ * @param path the test source root to add
+ */
public void addTestCompileSourceRoot(String path) {
- addPath(getTestCompileSourceRoots(), path);
+ addPath(testCompileSourceRoots, path);
+ }
+
+ /**
+ * Removes the specified path from the list of test compile source roots.
+ *
+ * @param path the test source root to remove
+ * @since 3.9.10
+ */
+ public void removeTestCompileSourceRoot(String path) {
+ removePath(testCompileSourceRoots, path);
}
+ /**
+ * Gets the list of compile source roots for this project.
+ * <p>
+ * <strong>Note:</strong> The collection returned by this method should
not be modified directly.
+ * Use {@link #addCompileSourceRoot(String)} and {@link
#removeCompileSourceRoot(String)} methods instead.
+ *
+ * @return a list of compile source roots
+ */
public List<String> getCompileSourceRoots() {
- return compileSourceRoots;
+ return new LoggingList<>(compileSourceRoots, "compileSourceRoots");
}
+ /**
+ * Gets the list of test compile source roots for this project.
+ * <p>
+ * <strong>Note:</strong> The collection returned by this method should
not be modified directly.
+ * Use {@link #addTestCompileSourceRoot(String)} and {@link
#removeTestCompileSourceRoot(String)} methods instead.
+ *
+ * @return a list of test compile source roots
+ */
public List<String> getTestCompileSourceRoots() {
- return testCompileSourceRoots;
+ return new LoggingList<>(testCompileSourceRoots,
"testCompileSourceRoots");
}
public List<String> getCompileClasspathElements() throws
DependencyResolutionRequiredException {
@@ -1120,6 +1188,190 @@ private static String getProjectReferenceId(String
groupId, String artifactId, S
return buffer.toString();
}
+ /**
+ * A List implementation that logs warnings when modified directly instead
of using the proper add/remove methods.
+ * This is a wrapper that delegates all operations to the underlying list,
so modifications to this list
+ * will affect the original list.
+ *
+ * @param <E> the type of elements in the list
+ * @since 3.9.10
+ */
+ private class LoggingList<E> extends AbstractList<E> {
+ private static final String DISABLE_WARNINGS_PROPERTY =
"maven.project.sourceRoots.warningsDisabled";
+ private final List<E> delegate;
+ private final String collectionName;
+
+ LoggingList(List<E> delegate, String collectionName) {
+ this.delegate = delegate;
+ this.collectionName = collectionName;
+ }
+
+ private void logWarning(String method) {
+ // Check if warnings are disabled
+ String property =
getProperties().getProperty(DISABLE_WARNINGS_PROPERTY);
+ if (property == null) {
+ property = System.getProperty(DISABLE_WARNINGS_PROPERTY);
+ }
+ if (Boolean.parseBoolean(property)) {
+ return;
+ }
+
+ LOGGER.warn("Direct modification of " + collectionName + " through
" + method
+ + "() is deprecated and will not work in Maven 4.0.0. "
+ + "Please use the add/remove methods instead. If you're
using a plugin that causes this warning, "
+ + "please upgrade to the latest version and report an
issue if the warning persists. "
+ + "To disable these warnings, set -D" +
DISABLE_WARNINGS_PROPERTY + "=true on the command line, "
+ + "in the .mvn/maven.config file, or in project POM
properties.");
+ // Log a stack trace to help identify the caller
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Stack trace", new Exception("Stack trace"));
+ }
+ }
+
+ @Override
+ public E get(int index) {
+ return delegate.get(index);
+ }
+
+ @Override
+ public int size() {
+ return delegate.size();
+ }
+
+ @Override
+ public E set(int index, E element) {
+ logWarning("set");
+ return delegate.set(index, element);
+ }
+
+ @Override
+ public void add(int index, E element) {
+ logWarning("add");
+ delegate.add(index, element);
+ }
+
+ @Override
+ public E remove(int index) {
+ logWarning("remove");
+ return delegate.remove(index);
+ }
+
+ @Override
+ public void clear() {
+ logWarning("clear");
+ delegate.clear();
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends E> c) {
+ logWarning("addAll");
+ return delegate.addAll(index, c);
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return new Iterator<E>() {
+ private final Iterator<E> it = delegate.iterator();
+
+ @Override
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ @Override
+ public E next() {
+ return it.next();
+ }
+
+ @Override
+ public void remove() {
+ logWarning("iterator.remove");
+ it.remove();
+ }
+ };
+ }
+
+ @Override
+ public ListIterator<E> listIterator() {
+ return listIterator(0);
+ }
+
+ @Override
+ public ListIterator<E> listIterator(int index) {
+ return new ListIterator<E>() {
+ private final ListIterator<E> it =
delegate.listIterator(index);
+
+ @Override
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ @Override
+ public E next() {
+ return it.next();
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ return it.hasPrevious();
+ }
+
+ @Override
+ public E previous() {
+ return it.previous();
+ }
+
+ @Override
+ public int nextIndex() {
+ return it.nextIndex();
+ }
+
+ @Override
+ public int previousIndex() {
+ return it.previousIndex();
+ }
+
+ @Override
+ public void remove() {
+ logWarning("listIterator.remove");
+ it.remove();
+ }
+
+ @Override
+ public void set(E e) {
+ logWarning("listIterator.set");
+ it.set(e);
+ }
+
+ @Override
+ public void add(E e) {
+ logWarning("listIterator.add");
+ it.add(e);
+ }
+ };
+ }
+
+ @Override
+ public List<E> subList(int fromIndex, int toIndex) {
+ return new LoggingList<>(delegate.subList(fromIndex, toIndex),
collectionName);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return delegate.equals(o);
+ }
+
+ @Override
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString();
+ }
+ }
+
/**
* Sets the value of the context value of this project identified by the
given key. If the supplied value is
* <code>null</code>, the context value is removed from this project.
Context values are intended to allow core