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.git
The following commit(s) were added to refs/heads/master by this push:
new 46cf946b6f Type derive (simpler) (#11380)
46cf946b6f is described below
commit 46cf946b6fcd5ff58fa208aa5b018128aec88695
Author: Tamas Cservenak <[email protected]>
AuthorDate: Thu Mar 19 14:42:58 2026 +0100
Type derive (simpler) (#11380)
Instead to "smear" this feature across Maven and Resolver classes, for
start let's keep it "confined" with single class: the TypeDeriver.
Later we can see where to go further with it.
This PR also includes bugfix, where Maven `DefaultType` implements
`ArtifactType`, while in reality it does not (violates contract by returning
`null` when no classifier present).
---
.../internal/ArtifactDescriptorReaderDelegate.java | 3 +-
.../internal/MavenSessionBuilderSupplier.java | 6 +-
.../repository/internal/type/DefaultType.java | 44 ++++--
.../repository/internal/type/TypeDeriver.java | 147 +++++++++++++++++++
.../DefaultRepositorySystemSessionFactory.java | 1 +
.../resolver/DefaultArtifactDescriptorReader.java | 6 +
.../impl/resolver/MavenSessionBuilderSupplier.java | 6 +-
.../maven/impl/resolver/type/DefaultType.java | 56 ++++++--
.../impl/resolver/type/DefaultTypeProvider.java | 3 +
.../maven/impl/resolver/type/TypeDeriver.java | 153 ++++++++++++++++++++
.../impl/resolver/type}/TypeRegistryAdapter.java | 23 +--
.../maven/impl/resolver/type/TypeDeriverTest.java | 156 +++++++++++++++++++++
12 files changed, 568 insertions(+), 36 deletions(-)
diff --git
a/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java
b/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java
index 068c697e79..5ccf74b589 100644
---
a/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java
+++
b/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java
@@ -96,7 +96,8 @@ public void populateResult(RepositorySystemSession session,
ArtifactDescriptorRe
private Dependency convert(org.apache.maven.model.Dependency dependency,
ArtifactTypeRegistry stereotypes) {
ArtifactType stereotype = stereotypes.get(dependency.getType());
if (stereotype == null) {
- stereotype = new DefaultType(dependency.getType(), Language.NONE,
dependency.getType(), null, false);
+ stereotype = new DefaultType(dependency.getType(), Language.NONE,
dependency.getType(), null, false)
+ .toArtifactType();
}
boolean system = dependency.getSystemPath() != null
diff --git
a/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSessionBuilderSupplier.java
b/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSessionBuilderSupplier.java
index 0ee5153321..5d1159f09e 100644
---
a/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSessionBuilderSupplier.java
+++
b/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSessionBuilderSupplier.java
@@ -25,6 +25,7 @@
import org.apache.maven.repository.internal.artifact.FatArtifactTraverser;
import
org.apache.maven.repository.internal.scopes.Maven4ScopeManagerConfiguration;
import org.apache.maven.repository.internal.type.DefaultTypeProvider;
+import org.apache.maven.repository.internal.type.TypeDeriver;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession.CloseableSession;
import org.eclipse.aether.RepositorySystemSession.SessionBuilder;
@@ -114,7 +115,8 @@ protected DependencyGraphTransformer
getDependencyGraphTransformer() {
new ConflictResolver(
new ConfigurableVersionSelector(), new
ManagedScopeSelector(getScopeManager()),
new SimpleOptionalitySelector(), new
ManagedScopeDeriver(getScopeManager())),
- new ManagedDependencyContextRefiner(getScopeManager()));
+ new ManagedDependencyContextRefiner(getScopeManager()),
+ new TypeDeriver());
}
/**
@@ -128,7 +130,7 @@ protected DependencyGraphTransformer
getDependencyGraphTransformer() {
*/
protected ArtifactTypeRegistry getArtifactTypeRegistry() {
DefaultArtifactTypeRegistry stereotypes = new
DefaultArtifactTypeRegistry();
- new DefaultTypeProvider().types().forEach(stereotypes::add);
+ new DefaultTypeProvider().types().forEach(t ->
stereotypes.add(t.toArtifactType()));
return stereotypes;
}
diff --git
a/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/type/DefaultType.java
b/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/type/DefaultType.java
index 016688ef4c..842b779d8b 100644
---
a/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/type/DefaultType.java
+++
b/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/type/DefaultType.java
@@ -42,7 +42,7 @@
* @deprecated since 4.0.0, use {@code maven-api-impl} jar instead
*/
@Deprecated(since = "4.0.0")
-public class DefaultType implements Type, ArtifactType {
+public class DefaultType implements Type {
private final String id;
private final Language language;
private final String extension;
@@ -80,11 +80,6 @@ public String id() {
return id;
}
- @Override
- public String getId() {
- return id();
- }
-
@Override
public Language getLanguage() {
return language;
@@ -105,13 +100,44 @@ public boolean isIncludesDependencies() {
return this.includesDependencies;
}
+ public Map<String, String> getProperties() {
+ return properties;
+ }
+
@Override
public Set<PathType> getPathTypes() {
return this.pathTypes;
}
- @Override
- public Map<String, String> getProperties() {
- return properties;
+ public ArtifactType toArtifactType() {
+ return new ArtifactTypeAdapter(this);
+ }
+
+ private static class ArtifactTypeAdapter implements ArtifactType {
+ private final DefaultType type;
+
+ private ArtifactTypeAdapter(DefaultType type) {
+ this.type = type;
+ }
+
+ @Override
+ public String getId() {
+ return type.id();
+ }
+
+ @Override
+ public String getExtension() {
+ return type.getExtension();
+ }
+
+ @Override
+ public String getClassifier() {
+ return type.getClassifier() == null ? "" : type.getClassifier();
+ }
+
+ @Override
+ public Map<String, String> getProperties() {
+ return type.getProperties();
+ }
}
}
diff --git
a/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/type/TypeDeriver.java
b/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/type/TypeDeriver.java
new file mode 100644
index 0000000000..2120b4a587
--- /dev/null
+++
b/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/type/TypeDeriver.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository.internal.type;
+
+import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.api.Type;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.ArtifactProperties;
+import org.eclipse.aether.artifact.ArtifactType;
+import org.eclipse.aether.artifact.ArtifactTypeRegistry;
+import org.eclipse.aether.collection.DependencyGraphTransformationContext;
+import org.eclipse.aether.collection.DependencyGraphTransformer;
+import org.eclipse.aether.graph.DependencyNode;
+import org.eclipse.aether.graph.DependencyVisitor;
+import org.eclipse.aether.util.graph.visitor.DependencyGraphDumper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Type deriver, that handles special case of "processor" type: if a
dependency node is of this type, all of its
+ * children need to be remapped to certain processor type as well, to end up
on proper path type.
+ *
+ * @since 4.0.0
+ * @deprecated since 4.0.0, this is internal detail of Maven.
+ */
+@Deprecated(since = "4.0.0")
+public class TypeDeriver implements DependencyGraphTransformer {
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ @Override
+ public DependencyNode transformGraph(DependencyNode root,
DependencyGraphTransformationContext context) {
+ if (logger.isDebugEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ root.accept(new DependencyGraphDumper(
+ l -> sb.append(l).append("\n"),
+ DependencyGraphDumper.defaultsWith(
+
List.of(DependencyGraphDumper.artifactProperties(List.of(ArtifactProperties.TYPE))))));
+ logger.debug("TYPES: Before transform:\n {}", sb);
+ }
+ root.accept(new
TypeDeriverVisitor(context.getSession().getArtifactTypeRegistry()));
+ if (logger.isDebugEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ root.accept(new DependencyGraphDumper(
+ l -> sb.append(l).append("\n"),
+ DependencyGraphDumper.defaultsWith(
+
List.of(DependencyGraphDumper.artifactProperties(List.of(ArtifactProperties.TYPE))))));
+ logger.debug("TYPES: After transform:\n {}", sb);
+ }
+ return root;
+ }
+
+ private static class TypeDeriverVisitor implements DependencyVisitor {
+ private final ArtifactTypeRegistry registry;
+ private final ArtifactType jar;
+ private final ArtifactType classpathJar;
+ private final ArtifactType modularJar;
+ private final ArtifactType processor;
+ private final ArtifactType classpathProcessor;
+ private final ArtifactType modularProcessor;
+ private final Set<String> needsDerive;
+ private final ArrayDeque<ArtifactType> stack;
+
+ private TypeDeriverVisitor(ArtifactTypeRegistry registry) {
+ this.registry = requireNonNull(registry);
+ this.jar = requireType(Type.JAR);
+ this.classpathJar = requireType(Type.CLASSPATH_JAR);
+ this.modularJar = requireType(Type.MODULAR_JAR);
+ this.processor = requireType(Type.PROCESSOR);
+ this.classpathProcessor = requireType(Type.CLASSPATH_PROCESSOR);
+ this.modularProcessor = requireType(Type.MODULAR_PROCESSOR);
+ this.needsDerive = Set.of(Type.PROCESSOR,
Type.CLASSPATH_PROCESSOR, Type.MODULAR_PROCESSOR);
+ this.stack = new ArrayDeque<>();
+ }
+
+ private ArtifactType requireType(String id) {
+ return requireNonNull(registry.get(id), "Type " + id + " not found
but is required");
+ }
+
+ @Override
+ public boolean visitEnter(DependencyNode node) {
+ ArtifactType currentType = jar;
+ if (node.getArtifact() != null) {
+ if
(node.getArtifact().getProperties().containsKey(ArtifactProperties.TYPE)) {
+ currentType = registry.get(node.getArtifact()
+ .getProperty(
+ ArtifactProperties.TYPE,
node.getArtifact().getExtension()));
+ if (currentType == null) {
+ currentType = jar;
+ }
+ }
+ if (!stack.isEmpty()) {
+ ArtifactType parentType = stack.peek();
+ if (needsDerive.contains(parentType.getId())) {
+ Artifact artifact = node.getArtifact();
+ Map<String, String> props = new
HashMap<>(artifact.getProperties());
+ ArtifactType derived = derive(parentType, currentType);
+ props.putAll(derived.getProperties());
+ node.setArtifact(artifact.setProperties(props));
+ }
+ }
+ }
+ stack.push(currentType);
+ return true;
+ }
+
+ @Override
+ public boolean visitLeave(DependencyNode node) {
+ stack.pop();
+ return true;
+ }
+
+ private ArtifactType derive(ArtifactType parentType, ArtifactType
currentType) {
+ ArtifactType result = currentType;
+ if (jar.getId().equals(currentType.getId())) {
+ result = processor;
+ } else if (classpathJar.getId().equals(currentType.getId())) {
+ result = classpathProcessor;
+ } else if (modularJar.getId().equals(currentType.getId())) {
+ result = modularProcessor;
+ }
+ return result;
+ }
+ }
+}
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
b/impl/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
index 541c8364ed..56e1566a01 100644
---
a/impl/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
+++
b/impl/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
@@ -40,6 +40,7 @@
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.impl.resolver.MavenSessionBuilderSupplier;
+import org.apache.maven.impl.resolver.type.TypeRegistryAdapter;
import org.apache.maven.internal.xml.XmlPlexusConfiguration;
import org.apache.maven.model.ModelBase;
import org.apache.maven.resolver.RepositorySystemSessionFactory;
diff --git
a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java
index 10c58e0fb8..4d0b65c594 100644
---
a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java
+++
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java
@@ -27,6 +27,7 @@
import java.util.Map;
import java.util.Objects;
+import org.apache.maven.api.Language;
import org.apache.maven.api.RemoteRepository;
import org.apache.maven.api.di.Inject;
import org.apache.maven.api.di.Named;
@@ -50,6 +51,7 @@
import org.apache.maven.impl.RequestTraceHelper;
import org.apache.maven.impl.model.ModelProblemUtils;
import org.apache.maven.impl.resolver.artifact.MavenArtifactProperties;
+import org.apache.maven.impl.resolver.type.DefaultType;
import org.eclipse.aether.RepositoryEvent;
import org.eclipse.aether.RepositoryEvent.EventType;
import org.eclipse.aether.RepositoryException;
@@ -382,6 +384,10 @@ private void populateResult(InternalSession session,
ArtifactDescriptorResult re
private Dependency convert(org.apache.maven.api.model.Dependency
dependency, ArtifactTypeRegistry stereotypes) {
ArtifactType stereotype = stereotypes.get(dependency.getType());
+ if (stereotype == null) {
+ stereotype = new DefaultType(dependency.getType(), Language.NONE,
dependency.getType(), null, false)
+ .toArtifactType();
+ }
boolean system = dependency.getSystemPath() != null
&& !dependency.getSystemPath().isEmpty();
diff --git
a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java
index 3145953644..f7b4c237dd 100644
---
a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java
+++
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java
@@ -26,6 +26,7 @@
import org.apache.maven.impl.resolver.scopes.Maven3ScopeManagerConfiguration;
import org.apache.maven.impl.resolver.scopes.Maven4ScopeManagerConfiguration;
import org.apache.maven.impl.resolver.type.DefaultTypeProvider;
+import org.apache.maven.impl.resolver.type.TypeDeriver;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession.CloseableSession;
import org.eclipse.aether.RepositorySystemSession.SessionBuilder;
@@ -110,7 +111,8 @@ protected DependencyGraphTransformer
getDependencyGraphTransformer() {
new ConflictResolver(
new ConfigurableVersionSelector(), new
ManagedScopeSelector(getScopeManager()),
new SimpleOptionalitySelector(), new
ManagedScopeDeriver(getScopeManager())),
- new ManagedDependencyContextRefiner(getScopeManager()));
+ new ManagedDependencyContextRefiner(getScopeManager()),
+ new TypeDeriver());
}
/**
@@ -124,7 +126,7 @@ protected DependencyGraphTransformer
getDependencyGraphTransformer() {
*/
protected ArtifactTypeRegistry getArtifactTypeRegistry() {
DefaultArtifactTypeRegistry stereotypes = new
DefaultArtifactTypeRegistry();
- new DefaultTypeProvider().types().forEach(stereotypes::add);
+ new DefaultTypeProvider().types().forEach(t ->
stereotypes.add(t.toArtifactType()));
return stereotypes;
}
diff --git
a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/DefaultType.java
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/DefaultType.java
index 52ec4ba87f..f9773f2a54 100644
---
a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/DefaultType.java
+++
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/DefaultType.java
@@ -36,11 +36,11 @@
import static java.util.Objects.requireNonNull;
/**
- * Default implementation of {@link Type} and Resolver {@link ArtifactType}.
+ * Default implementation of {@link Type} and adapter for Resolver {@link
ArtifactType}.
*
* @since 4.0.0
*/
-public class DefaultType implements Type, ArtifactType {
+public class DefaultType implements Type {
private final String id;
private final Language language;
private final String extension;
@@ -78,11 +78,6 @@ public String id() {
return id;
}
- @Override
- public String getId() {
- return id();
- }
-
@Override
public Language getLanguage() {
return language;
@@ -103,14 +98,13 @@ public boolean isIncludesDependencies() {
return this.includesDependencies;
}
- @Override
- public Set<PathType> getPathTypes() {
- return this.pathTypes;
+ public Map<String, String> getProperties() {
+ return properties;
}
@Override
- public Map<String, String> getProperties() {
- return properties;
+ public Set<PathType> getPathTypes() {
+ return this.pathTypes;
}
@Override
@@ -124,4 +118,42 @@ public String toString() {
+ pathTypes + ", properties="
+ properties + ']';
}
+
+ /**
+ * Adapts this instance to Resolver {@link ArtifactType}.
+ * <p>
+ * Note: one notable difference exists, the {@link #getClassifier()}
method behavior.
+ * Once that harmonized, this adapting can go away.
+ */
+ public ArtifactType toArtifactType() {
+ return new ArtifactTypeAdapter(this);
+ }
+
+ private static class ArtifactTypeAdapter implements ArtifactType {
+ private final DefaultType type;
+
+ private ArtifactTypeAdapter(DefaultType type) {
+ this.type = type;
+ }
+
+ @Override
+ public String getId() {
+ return type.id();
+ }
+
+ @Override
+ public String getExtension() {
+ return type.getExtension();
+ }
+
+ @Override
+ public String getClassifier() {
+ return type.getClassifier() == null ? "" : type.getClassifier();
+ }
+
+ @Override
+ public Map<String, String> getProperties() {
+ return type.getProperties();
+ }
+ }
}
diff --git
a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/DefaultTypeProvider.java
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/DefaultTypeProvider.java
index 9140c0bb79..b0eead6840 100644
---
a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/DefaultTypeProvider.java
+++
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/DefaultTypeProvider.java
@@ -27,6 +27,9 @@
import org.apache.maven.api.di.Named;
import org.apache.maven.api.spi.TypeProvider;
+/**
+ * Maven 4 default {@link TypeProvider} implementation.
+ */
@Named
public class DefaultTypeProvider implements TypeProvider {
@SuppressWarnings({"rawtypes", "unchecked"})
diff --git
a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/TypeDeriver.java
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/TypeDeriver.java
new file mode 100644
index 0000000000..2a83ed83b1
--- /dev/null
+++
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/TypeDeriver.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.impl.resolver.type;
+
+import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.api.Type;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.ArtifactProperties;
+import org.eclipse.aether.artifact.ArtifactType;
+import org.eclipse.aether.artifact.ArtifactTypeRegistry;
+import org.eclipse.aether.collection.DependencyGraphTransformationContext;
+import org.eclipse.aether.collection.DependencyGraphTransformer;
+import org.eclipse.aether.graph.DependencyNode;
+import org.eclipse.aether.graph.DependencyVisitor;
+import org.eclipse.aether.util.graph.visitor.DependencyGraphDumper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Type deriver, that handles special cases of "processor" (annotation
processor) node transitive dependencies: all
+ * children of "processor" type are "redirected" to corresponding processor
subtypes:
+ * <ul>
+ * <li>{@code jar -> processor}</li>
+ * <li>{@code classpathJar -> classpathProcessor}</li>
+ * <li>{@code modularJar -> modularProcessor}</li>
+ * </ul>
+ *
+ * Maven 4 introduces new types to describe intent of dependencies, and the
"processor" new type (and it's subtypes)
+ * will add processors and their dependencies to proper processor paths, as
modern Java versions require.
+ *
+ * @since 4.0.0
+ */
+public class TypeDeriver implements DependencyGraphTransformer {
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ @Override
+ public DependencyNode transformGraph(DependencyNode root,
DependencyGraphTransformationContext context) {
+ if (logger.isDebugEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ root.accept(new DependencyGraphDumper(
+ l -> sb.append(l).append("\n"),
+ DependencyGraphDumper.defaultsWith(
+
List.of(DependencyGraphDumper.artifactProperties(List.of(ArtifactProperties.TYPE))))));
+ logger.debug("TYPES: Before transform:\n {}", sb);
+ }
+ root.accept(new
TypeDeriverVisitor(context.getSession().getArtifactTypeRegistry()));
+ if (logger.isDebugEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ root.accept(new DependencyGraphDumper(
+ l -> sb.append(l).append("\n"),
+ DependencyGraphDumper.defaultsWith(
+
List.of(DependencyGraphDumper.artifactProperties(List.of(ArtifactProperties.TYPE))))));
+ logger.debug("TYPES: After transform:\n {}", sb);
+ }
+ return root;
+ }
+
+ private static class TypeDeriverVisitor implements DependencyVisitor {
+ private final ArtifactTypeRegistry registry;
+ private final ArtifactType jar;
+ private final ArtifactType classpathJar;
+ private final ArtifactType modularJar;
+ private final ArtifactType processor;
+ private final ArtifactType classpathProcessor;
+ private final ArtifactType modularProcessor;
+ private final Set<String> needsDerive;
+ private final ArrayDeque<ArtifactType> stack;
+
+ private TypeDeriverVisitor(ArtifactTypeRegistry registry) {
+ this.registry = requireNonNull(registry);
+ this.jar = requireType(Type.JAR);
+ this.classpathJar = requireType(Type.CLASSPATH_JAR);
+ this.modularJar = requireType(Type.MODULAR_JAR);
+ this.processor = requireType(Type.PROCESSOR);
+ this.classpathProcessor = requireType(Type.CLASSPATH_PROCESSOR);
+ this.modularProcessor = requireType(Type.MODULAR_PROCESSOR);
+ this.needsDerive = Set.of(Type.PROCESSOR,
Type.CLASSPATH_PROCESSOR, Type.MODULAR_PROCESSOR);
+ this.stack = new ArrayDeque<>();
+ }
+
+ private ArtifactType requireType(String id) {
+ return requireNonNull(registry.get(id), "Type " + id + " not found
but is required");
+ }
+
+ @Override
+ public boolean visitEnter(DependencyNode node) {
+ ArtifactType currentType = jar;
+ if (node.getArtifact() != null) {
+ if
(node.getArtifact().getProperties().containsKey(ArtifactProperties.TYPE)) {
+ currentType = registry.get(node.getArtifact()
+ .getProperty(
+ ArtifactProperties.TYPE,
node.getArtifact().getExtension()));
+ if (currentType == null) {
+ currentType = jar;
+ }
+ }
+ if (!stack.isEmpty()) {
+ ArtifactType parentType = stack.peek();
+ if (needsDerive.contains(parentType.getId())) {
+ Artifact artifact = node.getArtifact();
+ Map<String, String> props = new
HashMap<>(artifact.getProperties());
+ ArtifactType derived = derive(parentType, currentType);
+ props.putAll(derived.getProperties());
+ node.setArtifact(artifact.setProperties(props));
+ }
+ }
+ }
+ stack.push(currentType);
+ return true;
+ }
+
+ @Override
+ public boolean visitLeave(DependencyNode node) {
+ stack.pop();
+ return true;
+ }
+
+ private ArtifactType derive(ArtifactType parentType, ArtifactType
currentType) {
+ ArtifactType result = currentType;
+ if (jar.getId().equals(currentType.getId())) {
+ result = processor;
+ } else if (classpathJar.getId().equals(currentType.getId())) {
+ result = classpathProcessor;
+ } else if (modularJar.getId().equals(currentType.getId())) {
+ result = modularProcessor;
+ }
+ return result;
+ }
+ }
+}
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/TypeRegistryAdapter.java
similarity index 70%
rename from
impl/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java
rename to
impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/TypeRegistryAdapter.java
index b802e8a44c..31f2542dda 100644
---
a/impl/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java
+++
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/TypeRegistryAdapter.java
@@ -16,21 +16,23 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.maven.internal.aether;
+package org.apache.maven.impl.resolver.type;
import org.apache.maven.api.PathType;
import org.apache.maven.api.Type;
import org.apache.maven.api.services.TypeRegistry;
-import org.apache.maven.impl.resolver.type.DefaultType;
import org.eclipse.aether.artifact.ArtifactType;
import org.eclipse.aether.artifact.ArtifactTypeRegistry;
import static java.util.Objects.requireNonNull;
-class TypeRegistryAdapter implements ArtifactTypeRegistry {
+/**
+ * Adapter between Maven {@link TypeRegistry} and Resolver {@link
ArtifactTypeRegistry}.
+ */
+public class TypeRegistryAdapter implements ArtifactTypeRegistry {
private final TypeRegistry typeRegistry;
- TypeRegistryAdapter(TypeRegistry typeRegistry) {
+ public TypeRegistryAdapter(TypeRegistry typeRegistry) {
this.typeRegistry = requireNonNull(typeRegistry, "typeRegistry");
}
@@ -41,11 +43,12 @@ public ArtifactType get(String typeId) {
return artifactType;
}
return new DefaultType(
- type.id(),
- type.getLanguage(),
- type.getExtension(),
- type.getClassifier(),
- type.isIncludesDependencies(),
- type.getPathTypes().toArray(new PathType[0]));
+ type.id(),
+ type.getLanguage(),
+ type.getExtension(),
+ type.getClassifier(),
+ type.isIncludesDependencies(),
+ type.getPathTypes().toArray(new PathType[0]))
+ .toArtifactType();
}
}
diff --git
a/impl/maven-impl/src/test/java/org/apache/maven/impl/resolver/type/TypeDeriverTest.java
b/impl/maven-impl/src/test/java/org/apache/maven/impl/resolver/type/TypeDeriverTest.java
new file mode 100644
index 0000000000..2426b4536c
--- /dev/null
+++
b/impl/maven-impl/src/test/java/org/apache/maven/impl/resolver/type/TypeDeriverTest.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.impl.resolver.type;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.Type;
+import org.apache.maven.api.services.TypeRegistry;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.ArtifactProperties;
+import org.eclipse.aether.artifact.ArtifactType;
+import org.eclipse.aether.artifact.ArtifactTypeRegistry;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.graph.DefaultDependencyNode;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.graph.DependencyNode;
+import
org.eclipse.aether.internal.impl.collect.DefaultDependencyGraphTransformationContext;
+import org.eclipse.aether.util.graph.visitor.DependencyGraphDumper;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static java.util.Objects.requireNonNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class TypeDeriverTest {
+ private final ArtifactTypeRegistry typeRegistry = new
TypeRegistryAdapter(new TypeRegistry() {
+ private final Map<String, Type> types =
+ new
DefaultTypeProvider().types().stream().collect(Collectors.toMap(DefaultType::id,
t -> t));
+
+ @Override
+ public Optional<Type> lookup(String id) {
+ return Optional.ofNullable(types.get(id));
+ }
+ });
+ private final TypeDeriver subject = new TypeDeriver();
+
+ @Test
+ void project() throws Exception {
+ RepositorySystemSession session = mock(RepositorySystemSession.class);
+ when(session.getArtifactTypeRegistry()).thenReturn(typeRegistry);
+
+ ArtifactType jar = requireNonNull(typeRegistry.get(Type.JAR));
+ ArtifactType modularJar =
requireNonNull(typeRegistry.get(Type.MODULAR_JAR));
+ ArtifactType processor =
requireNonNull(typeRegistry.get(Type.PROCESSOR));
+
+ // root: "the project"
+ DefaultDependencyNode node = new DefaultDependencyNode(new
DefaultArtifact("project:project:1.0", jar));
+
+ // direct: a plain JAR dependency
+ DefaultDependencyNode d1 =
+ new DefaultDependencyNode(new Dependency(new
DefaultArtifact("deps:lib-a:1.0", jar), "compile"));
+ // direct: a plain JAR dependency
+ DefaultDependencyNode d2 =
+ new DefaultDependencyNode(new Dependency(new
DefaultArtifact("deps:lib-b:1.0", jar), "compile"));
+ // direct: a processor dependency
+ DefaultDependencyNode d3 = new DefaultDependencyNode(
+ new Dependency(new DefaultArtifact("deps:processor:1.0",
processor), "compile"));
+
+ // transitive: processor depends on JAR
+ DefaultDependencyNode d31 =
+ new DefaultDependencyNode(new Dependency(new
DefaultArtifact("tdeps:lib-a:1.0", jar), "compile"));
+ // transitive: processor depends on modularJar
+ DefaultDependencyNode d32 = new DefaultDependencyNode(
+ new Dependency(new DefaultArtifact("tdeps:lib-b:1.0",
modularJar), "compile"));
+ d3.setChildren(List.of(d31, d32));
+
+ node.setChildren(List.of(d1, d2, d3));
+
+ node.accept(new DependencyGraphDumper(
+ System.out::println,
+ DependencyGraphDumper.defaultsWith(
+
List.of(DependencyGraphDumper.artifactProperties(List.of(ArtifactProperties.TYPE))))));
+
+ DependencyNode transformed =
+ subject.transformGraph(node, new
DefaultDependencyGraphTransformationContext(session));
+
+ Assertions.assertNotNull(transformed);
+ transformed.accept(new DependencyGraphDumper(
+ System.out::println,
+ DependencyGraphDumper.defaultsWith(
+
List.of(DependencyGraphDumper.artifactProperties(List.of(ArtifactProperties.TYPE))))));
+
+ Assertions.assertEquals(Type.MODULAR_PROCESSOR,
d32.getArtifact().getProperty(ArtifactProperties.TYPE, ""));
+ }
+
+ @Test
+ void plugin() throws Exception {
+ RepositorySystemSession session = mock(RepositorySystemSession.class);
+ when(session.getArtifactTypeRegistry()).thenReturn(typeRegistry);
+
+ ArtifactType mavenPlugin =
requireNonNull(typeRegistry.get(Type.MAVEN_PLUGIN));
+ ArtifactType jar = requireNonNull(typeRegistry.get(Type.JAR));
+ ArtifactType classpathJar =
requireNonNull(typeRegistry.get(Type.CLASSPATH_JAR));
+ ArtifactType modularJar =
requireNonNull(typeRegistry.get(Type.MODULAR_JAR));
+ ArtifactType processor =
requireNonNull(typeRegistry.get(Type.PROCESSOR));
+
+ // root: "the plugin"
+ DefaultDependencyNode node = new DefaultDependencyNode(new
DefaultArtifact("plugin:plugin:1.0", mavenPlugin));
+
+ // direct: a plain JAR dependency
+ DefaultDependencyNode d1 =
+ new DefaultDependencyNode(new Dependency(new
DefaultArtifact("deps:lib-a:1.0", jar), "compile"));
+ // direct: a plain JAR dependency
+ DefaultDependencyNode d2 =
+ new DefaultDependencyNode(new Dependency(new
DefaultArtifact("deps:lib-b:1.0", jar), "compile"));
+ // direct: a processor dependency
+ DefaultDependencyNode d3 = new DefaultDependencyNode(
+ new Dependency(new DefaultArtifact("deps:processor:1.0",
processor), "compile"));
+
+ // transitive: processor depends on classpathJar
+ DefaultDependencyNode d31 = new DefaultDependencyNode(
+ new Dependency(new DefaultArtifact("tdeps:lib-a:1.0",
classpathJar), "compile"));
+ // transitive: processor depends on modularJar
+ DefaultDependencyNode d32 = new DefaultDependencyNode(
+ new Dependency(new DefaultArtifact("tdeps:lib-b:1.0",
modularJar), "compile"));
+ d3.setChildren(List.of(d31, d32));
+
+ node.setChildren(List.of(d1, d2, d3));
+
+ node.accept(new DependencyGraphDumper(
+ System.out::println,
+ DependencyGraphDumper.defaultsWith(
+
List.of(DependencyGraphDumper.artifactProperties(List.of(ArtifactProperties.TYPE))))));
+
+ DependencyNode transformed =
+ subject.transformGraph(node, new
DefaultDependencyGraphTransformationContext(session));
+
+ Assertions.assertNotNull(transformed);
+ transformed.accept(new DependencyGraphDumper(
+ System.out::println,
+ DependencyGraphDumper.defaultsWith(
+
List.of(DependencyGraphDumper.artifactProperties(List.of(ArtifactProperties.TYPE))))));
+
+ Assertions.assertEquals(Type.MODULAR_PROCESSOR,
d32.getArtifact().getProperty(ArtifactProperties.TYPE, ""));
+ }
+}