You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by cs...@apache.org on 2026/07/24 12:02:03 UTC
(maven-resolver) branch master updated: Enh: Allow validator factory to abstain (#2008)
This is an automated email from the ASF dual-hosted git repository.
cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
The following commit(s) were added to refs/heads/master by this push:
new f164aa904 Enh: Allow validator factory to abstain (#2008)
f164aa904 is described below
commit f164aa904ade545c015bbb2d880ebac0625a04b0
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Fri Jul 24 14:01:58 2026 +0200
Enh: Allow validator factory to abstain (#2008)
Changes:
* allow `ValidatorFactory` to "abstain" and return `NOOP`
* introduce alt execution path for managed dependencies (use cases varies)
* cache validators per session
Fixes: #2007
---
.../impl/DefaultRepositorySystemValidator.java | 289 ++++++++++++---------
.../DefaultRepositorySystemReentrancyTest.java | 6 +-
.../internal/impl/DefaultRepositorySystemTest.java | 2 +-
.../impl/DefaultRepositorySystemValidatorTest.java | 157 +++++++++++
.../eclipse/aether/spi/validator/Validator.java | 26 +-
.../aether/spi/validator/ValidatorFactory.java | 16 +-
.../aether/supplier/RepositorySystemSupplier.java | 10 +-
.../aether/supplier/RepositorySystemSupplier.java | 10 +-
8 files changed, 364 insertions(+), 152 deletions(-)
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemValidator.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemValidator.java
index 15c85f20d..0d99e88ba 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemValidator.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemValidator.java
@@ -25,7 +25,10 @@ import javax.inject.Singleton;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.eclipse.aether.Keys;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.collection.CollectRequest;
@@ -50,10 +53,11 @@ import static java.util.Objects.requireNonNull;
@Singleton
@Named
public class DefaultRepositorySystemValidator implements RepositorySystemValidator {
- private final List<ValidatorFactory> validatorFactories;
+ private static final Object SESSION_VALIDATORS = Keys.of(DefaultRepositorySystemValidator.class, "validators");
+ private final Map<String, ValidatorFactory> validatorFactories;
@Inject
- public DefaultRepositorySystemValidator(List<ValidatorFactory> validatorFactories) {
+ public DefaultRepositorySystemValidator(Map<String, ValidatorFactory> validatorFactories) {
this.validatorFactories = requireNonNull(validatorFactories, "validatorFactories cannot be null");
}
@@ -65,22 +69,35 @@ public class DefaultRepositorySystemValidator implements RepositorySystemValidat
}
}
+ @SuppressWarnings("unchecked")
+ private Validator newInstance(RepositorySystemSession session, String name, ValidatorFactory factory) {
+ if (session.getCache() != null) {
+ return ((ConcurrentHashMap<String, Validator>)
+ session.getCache().computeIfAbsent(session, SESSION_VALIDATORS, ConcurrentHashMap::new))
+ .computeIfAbsent(name, k -> requireNonNull(factory.newInstance(session)));
+ } else {
+ return requireNonNull(factory.newInstance(session));
+ }
+ }
+
@Override
public void validateVersionRequest(RepositorySystemSession session, VersionRequest request) {
ArrayList<Exception> exceptions = new ArrayList<>();
- for (ValidatorFactory factory : validatorFactories) {
- Validator validator = factory.newInstance(session);
- try {
- validator.validateArtifact(request.getArtifact());
- } catch (Exception e) {
- exceptions.add(e);
- }
- for (RemoteRepository repository : request.getRepositories()) {
+ for (Map.Entry<String, ValidatorFactory> entry : validatorFactories.entrySet()) {
+ Validator validator = newInstance(session, entry.getKey(), entry.getValue());
+ if (validator != ValidatorFactory.NOOP) {
try {
- validator.validateRemoteRepository(repository);
+ validator.validateArtifact(request.getArtifact());
} catch (Exception e) {
exceptions.add(e);
}
+ for (RemoteRepository repository : request.getRepositories()) {
+ try {
+ validator.validateRemoteRepository(repository);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
+ }
}
}
mayThrow(exceptions, "Invalid Version Request: " + request);
@@ -89,19 +106,21 @@ public class DefaultRepositorySystemValidator implements RepositorySystemValidat
@Override
public void validateVersionRangeRequest(RepositorySystemSession session, VersionRangeRequest request) {
ArrayList<Exception> exceptions = new ArrayList<>();
- for (ValidatorFactory factory : validatorFactories) {
- Validator validator = factory.newInstance(session);
- try {
- validator.validateArtifact(request.getArtifact());
- } catch (Exception e) {
- exceptions.add(e);
- }
- for (RemoteRepository repository : request.getRepositories()) {
+ for (Map.Entry<String, ValidatorFactory> entry : validatorFactories.entrySet()) {
+ Validator validator = newInstance(session, entry.getKey(), entry.getValue());
+ if (validator != ValidatorFactory.NOOP) {
try {
- validator.validateRemoteRepository(repository);
+ validator.validateArtifact(request.getArtifact());
} catch (Exception e) {
exceptions.add(e);
}
+ for (RemoteRepository repository : request.getRepositories()) {
+ try {
+ validator.validateRemoteRepository(repository);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
+ }
}
}
mayThrow(exceptions, "Invalid Version Range Request: " + request);
@@ -110,19 +129,21 @@ public class DefaultRepositorySystemValidator implements RepositorySystemValidat
@Override
public void validateArtifactDescriptorRequest(RepositorySystemSession session, ArtifactDescriptorRequest request) {
ArrayList<Exception> exceptions = new ArrayList<>();
- for (ValidatorFactory factory : validatorFactories) {
- Validator validator = factory.newInstance(session);
- try {
- validator.validateArtifact(request.getArtifact());
- } catch (Exception e) {
- exceptions.add(e);
- }
- for (RemoteRepository repository : request.getRepositories()) {
+ for (Map.Entry<String, ValidatorFactory> entry : validatorFactories.entrySet()) {
+ Validator validator = newInstance(session, entry.getKey(), entry.getValue());
+ if (validator != ValidatorFactory.NOOP) {
try {
- validator.validateRemoteRepository(repository);
+ validator.validateArtifact(request.getArtifact());
} catch (Exception e) {
exceptions.add(e);
}
+ for (RemoteRepository repository : request.getRepositories()) {
+ try {
+ validator.validateRemoteRepository(repository);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
+ }
}
}
mayThrow(exceptions, "Invalid Artifact Descriptor Request: " + request);
@@ -132,20 +153,22 @@ public class DefaultRepositorySystemValidator implements RepositorySystemValidat
public void validateArtifactRequests(
RepositorySystemSession session, Collection<? extends ArtifactRequest> requests) {
ArrayList<Exception> exceptions = new ArrayList<>();
- for (ValidatorFactory factory : validatorFactories) {
- Validator validator = factory.newInstance(session);
- for (ArtifactRequest request : requests) {
- try {
- validator.validateArtifact(request.getArtifact());
- } catch (Exception e) {
- exceptions.add(e);
- }
- for (RemoteRepository repository : request.getRepositories()) {
+ for (Map.Entry<String, ValidatorFactory> entry : validatorFactories.entrySet()) {
+ Validator validator = newInstance(session, entry.getKey(), entry.getValue());
+ if (validator != ValidatorFactory.NOOP) {
+ for (ArtifactRequest request : requests) {
try {
- validator.validateRemoteRepository(repository);
+ validator.validateArtifact(request.getArtifact());
} catch (Exception e) {
exceptions.add(e);
}
+ for (RemoteRepository repository : request.getRepositories()) {
+ try {
+ validator.validateRemoteRepository(repository);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
+ }
}
}
}
@@ -156,20 +179,22 @@ public class DefaultRepositorySystemValidator implements RepositorySystemValidat
public void validateMetadataRequests(
RepositorySystemSession session, Collection<? extends MetadataRequest> requests) {
ArrayList<Exception> exceptions = new ArrayList<>();
- for (ValidatorFactory factory : validatorFactories) {
- Validator validator = factory.newInstance(session);
- for (MetadataRequest request : requests) {
- try {
- validator.validateMetadata(request.getMetadata());
- } catch (Exception e) {
- exceptions.add(e);
- }
- try {
- if (request.getRepository() != null) {
- validator.validateRemoteRepository(request.getRepository());
+ for (Map.Entry<String, ValidatorFactory> entry : validatorFactories.entrySet()) {
+ Validator validator = newInstance(session, entry.getKey(), entry.getValue());
+ if (validator != ValidatorFactory.NOOP) {
+ for (MetadataRequest request : requests) {
+ try {
+ validator.validateMetadata(request.getMetadata());
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
+ try {
+ if (request.getRepository() != null) {
+ validator.validateRemoteRepository(request.getRepository());
+ }
+ } catch (Exception e) {
+ exceptions.add(e);
}
- } catch (Exception e) {
- exceptions.add(e);
}
}
}
@@ -179,41 +204,43 @@ public class DefaultRepositorySystemValidator implements RepositorySystemValidat
@Override
public void validateCollectRequest(RepositorySystemSession session, CollectRequest request) {
ArrayList<Exception> exceptions = new ArrayList<>();
- for (ValidatorFactory factory : validatorFactories) {
- Validator validator = factory.newInstance(session);
- if (request.getRootArtifact() != null) {
- try {
- validator.validateArtifact(request.getRootArtifact());
- } catch (Exception e) {
- exceptions.add(e);
+ for (Map.Entry<String, ValidatorFactory> entry : validatorFactories.entrySet()) {
+ Validator validator = newInstance(session, entry.getKey(), entry.getValue());
+ if (validator != ValidatorFactory.NOOP) {
+ if (request.getRootArtifact() != null) {
+ try {
+ validator.validateArtifact(request.getRootArtifact());
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
}
- }
- if (request.getRoot() != null) {
- try {
- validator.validateDependency(request.getRoot());
- } catch (Exception e) {
- exceptions.add(e);
+ if (request.getRoot() != null) {
+ try {
+ validator.validateDependency(request.getRoot());
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
}
- }
- for (Dependency dependency : request.getDependencies()) {
- try {
- validator.validateDependency(dependency);
- } catch (Exception e) {
- exceptions.add(e);
+ for (Dependency dependency : request.getDependencies()) {
+ try {
+ validator.validateDependency(dependency);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
}
- }
- for (Dependency managedDependency : request.getManagedDependencies()) {
- try {
- validator.validateDependency(managedDependency);
- } catch (Exception e) {
- exceptions.add(e);
+ for (Dependency managedDependency : request.getManagedDependencies()) {
+ try {
+ validator.validateManagedDependency(managedDependency);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
}
- }
- for (RemoteRepository repository : request.getRepositories()) {
- try {
- validator.validateRemoteRepository(repository);
- } catch (Exception e) {
- exceptions.add(e);
+ for (RemoteRepository repository : request.getRepositories()) {
+ try {
+ validator.validateRemoteRepository(repository);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
}
}
}
@@ -234,20 +261,22 @@ public class DefaultRepositorySystemValidator implements RepositorySystemValidat
@Override
public void validateInstallRequest(RepositorySystemSession session, InstallRequest request) {
ArrayList<Exception> exceptions = new ArrayList<>();
- for (ValidatorFactory factory : validatorFactories) {
- Validator validator = factory.newInstance(session);
- for (Artifact artifact : request.getArtifacts()) {
- try {
- validator.validateArtifact(artifact);
- } catch (Exception e) {
- exceptions.add(e);
+ for (Map.Entry<String, ValidatorFactory> entry : validatorFactories.entrySet()) {
+ Validator validator = newInstance(session, entry.getKey(), entry.getValue());
+ if (validator != ValidatorFactory.NOOP) {
+ for (Artifact artifact : request.getArtifacts()) {
+ try {
+ validator.validateArtifact(artifact);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
}
- }
- for (Metadata metadata : request.getMetadata()) {
- try {
- validator.validateMetadata(metadata);
- } catch (Exception e) {
- exceptions.add(e);
+ for (Metadata metadata : request.getMetadata()) {
+ try {
+ validator.validateMetadata(metadata);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
}
}
}
@@ -257,29 +286,31 @@ public class DefaultRepositorySystemValidator implements RepositorySystemValidat
@Override
public void validateDeployRequest(RepositorySystemSession session, DeployRequest request) {
ArrayList<Exception> exceptions = new ArrayList<>();
- for (ValidatorFactory factory : validatorFactories) {
- Validator validator = factory.newInstance(session);
- for (Artifact artifact : request.getArtifacts()) {
- try {
- validator.validateArtifact(artifact);
- } catch (Exception e) {
- exceptions.add(e);
+ for (Map.Entry<String, ValidatorFactory> entry : validatorFactories.entrySet()) {
+ Validator validator = newInstance(session, entry.getKey(), entry.getValue());
+ if (validator != ValidatorFactory.NOOP) {
+ for (Artifact artifact : request.getArtifacts()) {
+ try {
+ validator.validateArtifact(artifact);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
+ }
+ for (Metadata metadata : request.getMetadata()) {
+ try {
+ validator.validateMetadata(metadata);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
}
- }
- for (Metadata metadata : request.getMetadata()) {
try {
- validator.validateMetadata(metadata);
+ if (request.getRepository() != null) {
+ validator.validateRemoteRepository(request.getRepository());
+ }
} catch (Exception e) {
exceptions.add(e);
}
}
- try {
- if (request.getRepository() != null) {
- validator.validateRemoteRepository(request.getRepository());
- }
- } catch (Exception e) {
- exceptions.add(e);
- }
}
mayThrow(exceptions, "Invalid Deploy Request: " + request);
}
@@ -287,13 +318,15 @@ public class DefaultRepositorySystemValidator implements RepositorySystemValidat
@Override
public void validateLocalRepositories(RepositorySystemSession session, Collection<LocalRepository> repositories) {
ArrayList<Exception> exceptions = new ArrayList<>();
- for (ValidatorFactory factory : validatorFactories) {
- Validator validator = factory.newInstance(session);
- for (LocalRepository repository : repositories) {
- try {
- validator.validateLocalRepository(repository);
- } catch (Exception e) {
- exceptions.add(e);
+ for (Map.Entry<String, ValidatorFactory> entry : validatorFactories.entrySet()) {
+ Validator validator = newInstance(session, entry.getKey(), entry.getValue());
+ if (validator != ValidatorFactory.NOOP) {
+ for (LocalRepository repository : repositories) {
+ try {
+ validator.validateLocalRepository(repository);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
}
}
}
@@ -303,13 +336,15 @@ public class DefaultRepositorySystemValidator implements RepositorySystemValidat
@Override
public void validateRemoteRepositories(RepositorySystemSession session, Collection<RemoteRepository> repositories) {
ArrayList<Exception> exceptions = new ArrayList<>();
- for (ValidatorFactory factory : validatorFactories) {
- Validator validator = factory.newInstance(session);
- for (RemoteRepository repository : repositories) {
- try {
- validator.validateRemoteRepository(repository);
- } catch (Exception e) {
- exceptions.add(e);
+ for (Map.Entry<String, ValidatorFactory> entry : validatorFactories.entrySet()) {
+ Validator validator = newInstance(session, entry.getKey(), entry.getValue());
+ if (validator != ValidatorFactory.NOOP) {
+ for (RemoteRepository repository : repositories) {
+ try {
+ validator.validateRemoteRepository(repository);
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
}
}
}
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemReentrancyTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemReentrancyTest.java
index 6aa9e10de..bfb6d356b 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemReentrancyTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemReentrancyTest.java
@@ -100,7 +100,7 @@ public class DefaultRepositorySystemReentrancyTest {
new DefaultRepositoryKeyFunctionFactory()),
new DefaultRepositorySystemLifecycle(),
Collections.emptyMap(),
- new DefaultRepositorySystemValidator(Collections.singletonList(countingValidator)));
+ new DefaultRepositorySystemValidator(Collections.singletonMap("counting", countingValidator)));
session = TestUtils.newSession();
}
@@ -162,7 +162,7 @@ public class DefaultRepositorySystemReentrancyTest {
new DefaultRepositorySystemLifecycle(),
Collections.emptyMap(),
new DefaultRepositorySystemValidator(
- Collections.singletonList(EXPRESSION_REJECTING_VALIDATOR_FACTORY)));
+ Collections.singletonMap("expressionRejecting", EXPRESSION_REJECTING_VALIDATOR_FACTORY)));
// An outermost call with an uninterpolated expression MUST fail validation
VersionRangeRequest outerBadRequest =
@@ -221,7 +221,7 @@ public class DefaultRepositorySystemReentrancyTest {
new DefaultRepositoryKeyFunctionFactory()),
new DefaultRepositorySystemLifecycle(),
Collections.singletonMap("test", decoratorFactory),
- new DefaultRepositorySystemValidator(Collections.emptyList()));
+ new DefaultRepositorySystemValidator(Collections.emptyMap()));
// Outermost call: decorator should run
ArtifactDescriptorRequest outerRequest =
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java
index 4fa1953d5..ff033e0b6 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java
@@ -69,7 +69,7 @@ public class DefaultRepositorySystemTest {
new DefaultRepositoryKeyFunctionFactory()),
new DefaultRepositorySystemLifecycle(),
Collections.emptyMap(),
- new DefaultRepositorySystemValidator(Collections.emptyList()));
+ new DefaultRepositorySystemValidator(Collections.emptyMap()));
session = TestUtils.newSession();
}
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemValidatorTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemValidatorTest.java
new file mode 100644
index 000000000..bd8d0ddfb
--- /dev/null
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemValidatorTest.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eclipse.aether.internal.impl;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.aether.DefaultRepositoryCache;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.collection.CollectRequest;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.internal.test.util.TestUtils;
+import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
+import org.eclipse.aether.spi.validator.Validator;
+import org.eclipse.aether.spi.validator.ValidatorFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class DefaultRepositorySystemValidatorTest {
+ @Test
+ void abstain() {
+ DefaultRepositorySystemValidator validator = new DefaultRepositorySystemValidator(
+ Collections.singletonMap("abstain", session -> ValidatorFactory.NOOP));
+ ArtifactDescriptorRequest request =
+ new ArtifactDescriptorRequest(new DefaultArtifact("foo:bar:1.0"), Collections.emptyList(), "test");
+ assertDoesNotThrow(() -> validator.validateArtifactDescriptorRequest(TestUtils.newSession(), request));
+ }
+
+ @Test
+ void fail() {
+ DefaultRepositorySystemValidator validator =
+ new DefaultRepositorySystemValidator(Collections.singletonMap("fail", session -> new Validator() {
+ @Override
+ public void validateArtifact(Artifact artifact) throws IllegalArgumentException {
+ throw new IllegalArgumentException("Artifact validation failed");
+ }
+ }));
+ ArtifactDescriptorRequest request =
+ new ArtifactDescriptorRequest(new DefaultArtifact("foo:bar:1.0"), Collections.emptyList(), "test");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> validator.validateArtifactDescriptorRequest(TestUtils.newSession(), request));
+ }
+
+ @Test
+ void withCaching() {
+ final ConcurrentHashMap<Integer, AtomicInteger> instanceCounter = new ConcurrentHashMap<>();
+ DefaultRepositorySystemValidator validator =
+ new DefaultRepositorySystemValidator(Collections.singletonMap("counter", session -> new Validator() {
+ @Override
+ public void validateArtifact(Artifact artifact) throws IllegalArgumentException {
+ instanceCounter
+ .computeIfAbsent(System.identityHashCode(this), k -> new AtomicInteger(0))
+ .incrementAndGet();
+ }
+ }));
+ DefaultRepositorySystemSession sameSession = TestUtils.newSession();
+ sameSession.setCache(new DefaultRepositoryCache()); // with cache
+ assertDoesNotThrow(() -> validator.validateArtifactDescriptorRequest(
+ sameSession,
+ new ArtifactDescriptorRequest(new DefaultArtifact("foo:bar:1.0"), Collections.emptyList(), "test")));
+ assertDoesNotThrow(() -> validator.validateArtifactDescriptorRequest(
+ sameSession,
+ new ArtifactDescriptorRequest(new DefaultArtifact("baz:foo:1.0"), Collections.emptyList(), "test")));
+ // one instance is
+ assertEquals(1, instanceCounter.size());
+ // used twice
+ assertEquals(
+ 2,
+ instanceCounter
+ .get(instanceCounter.keySet().stream().iterator().next())
+ .get());
+ }
+
+ @Test
+ void withoutCaching() {
+ final ConcurrentHashMap<Integer, AtomicInteger> instanceCounter = new ConcurrentHashMap<>();
+ DefaultRepositorySystemValidator validator =
+ new DefaultRepositorySystemValidator(Collections.singletonMap("counter", session -> new Validator() {
+ @Override
+ public void validateArtifact(Artifact artifact) throws IllegalArgumentException {
+ instanceCounter
+ .computeIfAbsent(System.identityHashCode(this), k -> new AtomicInteger(0))
+ .incrementAndGet();
+ }
+ }));
+ DefaultRepositorySystemSession sameSession = TestUtils.newSession();
+ sameSession.setCache(null); // without cache
+ assertDoesNotThrow(() -> validator.validateArtifactDescriptorRequest(
+ sameSession,
+ new ArtifactDescriptorRequest(new DefaultArtifact("foo:bar:1.0"), Collections.emptyList(), "test")));
+ assertDoesNotThrow(() -> validator.validateArtifactDescriptorRequest(
+ sameSession,
+ new ArtifactDescriptorRequest(new DefaultArtifact("baz:foo:1.0"), Collections.emptyList(), "test")));
+ // two instances
+ assertEquals(2, instanceCounter.size());
+ for (AtomicInteger counter : instanceCounter.values()) {
+ // each used once
+ assertEquals(1, counter.get());
+ }
+ }
+
+ @Test
+ void dependencies() {
+ final List<Dependency> dependencies =
+ Collections.singletonList(new Dependency(new DefaultArtifact("foo:bar:1.0"), "compile"));
+ final List<Dependency> managedDependencies =
+ Collections.singletonList(new Dependency(new DefaultArtifact("baz:foo:1.0"), "compile"));
+
+ final AtomicInteger validateDependencies = new AtomicInteger(0);
+ final AtomicInteger validateManagedDependencies = new AtomicInteger(0);
+ DefaultRepositorySystemValidator validator = new DefaultRepositorySystemValidator(Collections.singletonMap(
+ "dependencies", session -> new Validator() {
+ @Override
+ public void validateDependency(Dependency dependency) throws IllegalArgumentException {
+ assertTrue(dependencies.contains(dependency));
+ validateDependencies.incrementAndGet();
+ }
+
+ @Override
+ public void validateManagedDependency(Dependency managedDependency)
+ throws IllegalArgumentException {
+ assertTrue(managedDependencies.contains(managedDependency));
+ validateManagedDependencies.incrementAndGet();
+ }
+ }));
+ assertDoesNotThrow(() -> validator.validateCollectRequest(
+ TestUtils.newSession(),
+ new CollectRequest(dependencies, managedDependencies, Collections.emptyList())));
+ assertEquals(1, validateDependencies.get());
+ assertEquals(1, validateManagedDependencies.get());
+ }
+}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/Validator.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/Validator.java
index b41757609..16778c934 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/Validator.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/Validator.java
@@ -33,7 +33,7 @@ public interface Validator {
/**
* Validates artifact.
*
- * @param artifact The artifact to validate, never {@code null}.
+ * @param artifact the artifact to validate, never {@code null}.
* @throws IllegalArgumentException if artifact is invalid.
*/
default void validateArtifact(Artifact artifact) throws IllegalArgumentException {}
@@ -41,23 +41,37 @@ public interface Validator {
/**
* Validates metadata.
*
- * @param metadata The metadata to validate, never {@code null}.
- * @throws IllegalArgumentException if artifact is invalid.
+ * @param metadata the metadata to validate, never {@code null}.
+ * @throws IllegalArgumentException if metadata is invalid.
*/
default void validateMetadata(Metadata metadata) throws IllegalArgumentException {}
/**
* Validates dependency.
*
- * @param dependency The dependency to validate, never {@code null}.
+ * @param dependency the dependency to validate, never {@code null}.
* @throws IllegalArgumentException if dependency is invalid.
*/
default void validateDependency(Dependency dependency) throws IllegalArgumentException {}
+ /**
+ * Validates managed dependency.
+ * <em>Important:</em> They are declarative constraints (version/scope/exclusion overrides) that only take effect
+ * when a matching dependency is encountered during collection. Validating them eagerly may reject valid builds
+ * where a BOM imports managed dependencies with uninterpolated property expressions (e.g. {@code ${osgi.version}})
+ * that are never actually used. If a managed dependency IS matched and its coordinates are invalid, the error
+ * will surface naturally during version resolution or artifact resolution.
+ *
+ * @param managedDependency the managed dependency to validate, never {@code null}.
+ * @throws IllegalArgumentException if dependency is invalid.
+ * @since 2.0.22
+ */
+ default void validateManagedDependency(Dependency managedDependency) throws IllegalArgumentException {}
+
/**
* Validates local repository.
*
- * @param localRepository The local repository to validate, never {@code null}.
+ * @param localRepository the local repository to validate, never {@code null}.
* @throws IllegalArgumentException if local repository is invalid.
*/
default void validateLocalRepository(LocalRepository localRepository) throws IllegalArgumentException {}
@@ -65,7 +79,7 @@ public interface Validator {
/**
* Validates remote repository.
*
- * @param remoteRepository The remote repository to validate, never {@code null}.
+ * @param remoteRepository the remote repository to validate, never {@code null}.
* @throws IllegalArgumentException if remote repository is invalid.
*/
default void validateRemoteRepository(RemoteRepository remoteRepository) throws IllegalArgumentException {}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/ValidatorFactory.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/ValidatorFactory.java
index 23e59a8f6..7221d40e9 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/ValidatorFactory.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/ValidatorFactory.java
@@ -26,11 +26,21 @@ import org.eclipse.aether.RepositorySystemSession;
* @since 2.0.8
*/
public interface ValidatorFactory {
+
+ /**
+ * The no-op (does not validate anything) instance of validator.
+ *
+ * @since 2.0.22
+ */
+ Validator NOOP = new Validator() {};
+
/**
- * Creates a new validator for the session.
+ * Creates a new validator for the session, or {@link #NOOP} to abstain from validation. Factory is consulted
+ * once per session (if cache present in session) and returned instances are cached and reused
+ * across single session.
*
- * @param session The repository system session from which to configure the validator, must not be {@code null}.
- * @return The validator for the session, never {@code null}.
+ * @param session the repository system session from which to configure the validator, must not be {@code null}.
+ * @return the validator to be used for the session, or {@link #NOOP} to abstain from validation, never {@code null}.
*/
Validator newInstance(RepositorySystemSession session);
}
diff --git a/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java b/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
index bff9ca9a1..4a7b70f14 100644
--- a/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
+++ b/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
@@ -18,9 +18,7 @@
*/
package org.eclipse.aether.supplier;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@@ -1131,9 +1129,9 @@ public class RepositorySystemSupplier implements Supplier<RepositorySystem> {
return new DefaultModelCacheFactory();
}
- private List<ValidatorFactory> validatorFactories;
+ private Map<String, ValidatorFactory> validatorFactories;
- public final List<ValidatorFactory> getValidatorFactories() {
+ public final Map<String, ValidatorFactory> getValidatorFactories() {
checkClosed();
if (validatorFactories == null) {
validatorFactories = createValidatorFactories();
@@ -1141,8 +1139,8 @@ public class RepositorySystemSupplier implements Supplier<RepositorySystem> {
return validatorFactories;
}
- protected List<ValidatorFactory> createValidatorFactories() {
- return new ArrayList<>();
+ protected Map<String, ValidatorFactory> createValidatorFactories() {
+ return new HashMap<>();
}
private RepositorySystemValidator repositorySystemValidator;
diff --git a/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java b/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
index 3c78121fe..637b21e5a 100644
--- a/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
+++ b/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
@@ -18,10 +18,8 @@
*/
package org.eclipse.aether.supplier;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@@ -1156,9 +1154,9 @@ public class RepositorySystemSupplier implements Supplier<RepositorySystem> {
return new DefaultModelCacheFactory();
}
- private List<ValidatorFactory> validatorFactories;
+ private Map<String, ValidatorFactory> validatorFactories;
- public final List<ValidatorFactory> getValidatorFactories() {
+ public final Map<String, ValidatorFactory> getValidatorFactories() {
checkClosed();
if (validatorFactories == null) {
validatorFactories = createValidatorFactories();
@@ -1166,8 +1164,8 @@ public class RepositorySystemSupplier implements Supplier<RepositorySystem> {
return validatorFactories;
}
- protected List<ValidatorFactory> createValidatorFactories() {
- return new ArrayList<>();
+ protected Map<String, ValidatorFactory> createValidatorFactories() {
+ return new HashMap<>();
}
private RepositorySystemValidator repositorySystemValidator;