This is an automated email from the ASF dual-hosted git repository.
sjaranowski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-dependency-analyzer.git
The following commit(s) were added to refs/heads/master by this push:
new 064fa0e [MSHARED-1407] Track dependency usage by referencing classes
(#125)
064fa0e is described below
commit 064fa0e4494b826ea58952cf63be02ce3e18bfe4
Author: Jared Stehler <[email protected]>
AuthorDate: Mon Jun 3 12:55:09 2024 -0400
[MSHARED-1407] Track dependency usage by referencing classes (#125)
---
.../analyzer/DefaultProjectDependencyAnalyzer.java | 47 ++++++-----
.../dependency/analyzer/DependencyAnalyzer.java | 17 +++-
.../dependency/analyzer/DependencyUsage.java | 92 ++++++++++++++++++++++
.../analyzer/ProjectDependencyAnalysis.java | 33 +++++---
.../analyzer/asm/ASMDependencyAnalyzer.java | 5 +-
.../analyzer/asm/DefaultAnnotationVisitor.java | 11 ++-
.../analyzer/asm/DefaultClassVisitor.java | 24 +++---
.../analyzer/asm/DefaultFieldVisitor.java | 8 +-
.../analyzer/asm/DefaultMethodVisitor.java | 38 +++++----
.../analyzer/asm/DefaultSignatureVisitor.java | 8 +-
.../analyzer/asm/DependencyClassFileVisitor.java | 26 ++++--
.../dependency/analyzer/asm/ResultCollector.java | 47 +++++++----
.../analyzer/asm/DependencyVisitorTest.java | 13 +--
13 files changed, 273 insertions(+), 96 deletions(-)
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzer.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzer.java
index c792571..b36bd54 100644
---
a/src/main/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzer.java
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzer.java
@@ -36,6 +36,7 @@ import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
+import java.util.stream.Collectors;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.project.MavenProject;
@@ -68,17 +69,17 @@ public class DefaultProjectDependencyAnalyzer implements
ProjectDependencyAnalyz
ClassesPatterns excludedClassesPatterns = new
ClassesPatterns(excludedClasses);
Map<Artifact, Set<String>> artifactClassMap =
buildArtifactClassMap(project, excludedClassesPatterns);
- Set<String> mainDependencyClasses =
buildMainDependencyClasses(project, excludedClassesPatterns);
- Set<String> testDependencyClasses =
buildTestDependencyClasses(project, excludedClassesPatterns);
+ Set<DependencyUsage> mainDependencyClasses =
buildMainDependencyClasses(project, excludedClassesPatterns);
+ Set<DependencyUsage> testDependencyClasses =
buildTestDependencyClasses(project, excludedClassesPatterns);
- Set<String> dependencyClasses = new HashSet<>();
+ Set<DependencyUsage> dependencyClasses = new HashSet<>();
dependencyClasses.addAll(mainDependencyClasses);
dependencyClasses.addAll(testDependencyClasses);
- Set<String> testOnlyDependencyClasses =
+ Set<DependencyUsage> testOnlyDependencyClasses =
buildTestOnlyDependencyClasses(mainDependencyClasses,
testDependencyClasses);
- Map<Artifact, Set<String>> usedArtifacts =
buildUsedArtifacts(artifactClassMap, dependencyClasses);
+ Map<Artifact, Set<DependencyUsage>> usedArtifacts =
buildUsedArtifacts(artifactClassMap, dependencyClasses);
Set<Artifact> mainUsedArtifacts =
buildUsedArtifacts(artifactClassMap,
mainDependencyClasses).keySet();
@@ -90,7 +91,7 @@ public class DefaultProjectDependencyAnalyzer implements
ProjectDependencyAnalyz
Set<Artifact> usedDeclaredArtifacts = new
LinkedHashSet<>(declaredArtifacts);
usedDeclaredArtifacts.retainAll(usedArtifacts.keySet());
- Map<Artifact, Set<String>> usedUndeclaredArtifactsWithClasses =
new LinkedHashMap<>(usedArtifacts);
+ Map<Artifact, Set<DependencyUsage>>
usedUndeclaredArtifactsWithClasses = new LinkedHashMap<>(usedArtifacts);
Set<Artifact> usedUndeclaredArtifacts =
removeAll(usedUndeclaredArtifactsWithClasses.keySet(),
declaredArtifacts);
usedUndeclaredArtifactsWithClasses.keySet().retainAll(usedUndeclaredArtifacts);
@@ -190,29 +191,33 @@ public class DefaultProjectDependencyAnalyzer implements
ProjectDependencyAnalyz
return artifactClassMap;
}
- private static Set<String> buildTestOnlyDependencyClasses(
- Set<String> mainDependencyClasses, Set<String>
testDependencyClasses) {
- Set<String> testOnlyDependencyClasses = new
HashSet<>(testDependencyClasses);
- testOnlyDependencyClasses.removeAll(mainDependencyClasses);
+ private static Set<DependencyUsage> buildTestOnlyDependencyClasses(
+ Set<DependencyUsage> mainDependencyClasses, Set<DependencyUsage>
testDependencyClasses) {
+ Set<DependencyUsage> testOnlyDependencyClasses = new
HashSet<>(testDependencyClasses);
+ Set<String> mainDepClassNames = mainDependencyClasses.stream()
+ .map(DependencyUsage::getDependencyClass)
+ .collect(Collectors.toSet());
+ testOnlyDependencyClasses.removeIf(u ->
mainDepClassNames.contains(u.getDependencyClass()));
return testOnlyDependencyClasses;
}
- private Set<String> buildMainDependencyClasses(MavenProject project,
ClassesPatterns excludedClasses)
+ private Set<DependencyUsage> buildMainDependencyClasses(MavenProject
project, ClassesPatterns excludedClasses)
throws IOException {
String outputDirectory = project.getBuild().getOutputDirectory();
return buildDependencyClasses(outputDirectory, excludedClasses);
}
- private Set<String> buildTestDependencyClasses(MavenProject project,
ClassesPatterns excludedClasses)
+ private Set<DependencyUsage> buildTestDependencyClasses(MavenProject
project, ClassesPatterns excludedClasses)
throws IOException {
String testOutputDirectory =
project.getBuild().getTestOutputDirectory();
return buildDependencyClasses(testOutputDirectory, excludedClasses);
}
- private Set<String> buildDependencyClasses(String path, ClassesPatterns
excludedClasses) throws IOException {
+ private Set<DependencyUsage> buildDependencyClasses(String path,
ClassesPatterns excludedClasses)
+ throws IOException {
URL url = new File(path).toURI().toURL();
- return dependencyAnalyzer.analyze(url, excludedClasses);
+ return dependencyAnalyzer.analyzeUsages(url, excludedClasses);
}
private static Set<Artifact> buildDeclaredArtifacts(MavenProject project) {
@@ -225,20 +230,20 @@ public class DefaultProjectDependencyAnalyzer implements
ProjectDependencyAnalyz
return declaredArtifacts;
}
- private static Map<Artifact, Set<String>> buildUsedArtifacts(
- Map<Artifact, Set<String>> artifactClassMap, Set<String>
dependencyClasses) {
- Map<Artifact, Set<String>> usedArtifacts = new HashMap<>();
+ private static Map<Artifact, Set<DependencyUsage>> buildUsedArtifacts(
+ Map<Artifact, Set<String>> artifactClassMap, Set<DependencyUsage>
dependencyClasses) {
+ Map<Artifact, Set<DependencyUsage>> usedArtifacts = new HashMap<>();
- for (String className : dependencyClasses) {
- Artifact artifact = findArtifactForClassName(artifactClassMap,
className);
+ for (DependencyUsage classUsage : dependencyClasses) {
+ Artifact artifact = findArtifactForClassName(artifactClassMap,
classUsage.getDependencyClass());
if (artifact != null) {
- Set<String> classesFromArtifact = usedArtifacts.get(artifact);
+ Set<DependencyUsage> classesFromArtifact =
usedArtifacts.get(artifact);
if (classesFromArtifact == null) {
classesFromArtifact = new HashSet<>();
usedArtifacts.put(artifact, classesFromArtifact);
}
- classesFromArtifact.add(className);
+ classesFromArtifact.add(classUsage);
}
}
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyAnalyzer.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyAnalyzer.java
index 22a6a27..e73bc56 100644
---
a/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyAnalyzer.java
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyAnalyzer.java
@@ -21,6 +21,7 @@ package org.apache.maven.shared.dependency.analyzer;
import java.io.IOException;
import java.net.URL;
import java.util.Set;
+import java.util.stream.Collectors;
/**
* Gets the set of classes referenced by a library given either as a jar file
or an exploded directory.
@@ -48,5 +49,19 @@ public interface DependencyAnalyzer {
* @return the set of class names referenced by the library
* @throws IOException if an error occurs reading a JAR or .class file
*/
- Set<String> analyze(URL url, ClassesPatterns excludeClasses) throws
IOException;
+ default Set<String> analyze(URL url, ClassesPatterns excludeClasses)
throws IOException {
+ return analyzeUsages(url, excludeClasses).stream()
+ .map(DependencyUsage::getDependencyClass)
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * <p>analyzeUsages.</p>
+ *
+ * @param url the JAR file or directory to analyze
+ * @return the set of class names referenced by the library, paired with
the
+ * classes declaring those references.
+ * @throws IOException if an error occurs reading a JAR or .class file
+ */
+ Set<DependencyUsage> analyzeUsages(URL url, ClassesPatterns
excludeClasses) throws IOException;
}
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyUsage.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyUsage.java
new file mode 100644
index 0000000..6b2109d
--- /dev/null
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyUsage.java
@@ -0,0 +1,92 @@
+/*
+ * 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.shared.dependency.analyzer;
+
+/**
+ * Usage of a dependency class by a project class.
+ *
+ * @author <a href="mailto:[email protected]">Jonathan Haber</a>
+ */
+public class DependencyUsage {
+
+ private final String dependencyClass;
+
+ private final String usedBy;
+
+ public DependencyUsage(String dependencyClass, String usedBy) {
+ this.dependencyClass = dependencyClass;
+ this.usedBy = usedBy;
+ }
+
+ /**
+ * @return the dependency class used by the project class
+ */
+ public String getDependencyClass() {
+ return dependencyClass;
+ }
+
+ /**
+ * @return the project class using the dependency class
+ */
+ public String getUsedBy() {
+ return usedBy;
+ }
+
+ /*
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ int hashCode = dependencyClass.hashCode();
+ hashCode = (hashCode * 37) + usedBy.hashCode();
+
+ return hashCode;
+ }
+
+ /*
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object object) {
+ if (object instanceof DependencyUsage) {
+ DependencyUsage usage = (DependencyUsage) object;
+
+ return getDependencyClass().equals(usage.getDependencyClass())
+ && getUsedBy().equals(usage.getUsedBy());
+ }
+
+ return false;
+ }
+
+ /*
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append("dependencyClass=").append(getDependencyClass());
+ buffer.append(",");
+ buffer.append("usedBy=").append(getUsedBy());
+
+ buffer.insert(0, "[");
+ buffer.insert(0, getClass().getName());
+
+ buffer.append("]");
+
+ return buffer.toString();
+ }
+}
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysis.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysis.java
index 1f71550..9e63cff 100644
---
a/src/main/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysis.java
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysis.java
@@ -26,6 +26,7 @@ import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
import org.apache.maven.artifact.Artifact;
@@ -39,7 +40,7 @@ public class ProjectDependencyAnalysis {
private final Set<Artifact> usedDeclaredArtifacts;
- private final Map<Artifact, Set<String>> usedUndeclaredArtifacts;
+ private final Map<Artifact, Set<DependencyUsage>> usedUndeclaredArtifacts;
private final Set<Artifact> unusedDeclaredArtifacts;
@@ -49,7 +50,7 @@ public class ProjectDependencyAnalysis {
* <p>Constructor for ProjectDependencyAnalysis.</p>
*/
public ProjectDependencyAnalysis() {
- this(null, (Map<Artifact, Set<String>>) null, null, null);
+ this(null, (Map<Artifact, Set<DependencyUsage>>) null, null, null);
}
/**
@@ -88,7 +89,7 @@ public class ProjectDependencyAnalysis {
public ProjectDependencyAnalysis(
Set<Artifact> usedDeclaredArtifacts,
- Map<Artifact, Set<String>> usedUndeclaredArtifacts,
+ Map<Artifact, Set<DependencyUsage>> usedUndeclaredArtifacts,
Set<Artifact> unusedDeclaredArtifacts,
Set<Artifact> testArtifactsWithNonTestScope) {
this.usedDeclaredArtifacts = safeCopy(usedDeclaredArtifacts);
@@ -121,6 +122,20 @@ public class ProjectDependencyAnalysis {
* @return artifacts used but not declared
*/
public Map<Artifact, Set<String>> getUsedUndeclaredArtifactsWithClasses() {
+ Map<Artifact, Set<String>> usedUndeclaredArtifactsWithClasses = new
HashMap<>();
+
+ for (Map.Entry<Artifact, Set<DependencyUsage>> entry :
usedUndeclaredArtifacts.entrySet()) {
+ usedUndeclaredArtifactsWithClasses.put(
+ entry.getKey(),
+ entry.getValue().stream()
+ .map(DependencyUsage::getDependencyClass)
+ .collect(Collectors.toSet()));
+ }
+
+ return usedUndeclaredArtifactsWithClasses;
+ }
+
+ public Map<Artifact, Set<DependencyUsage>>
getUsedUndeclaredArtifactsWithUsages() {
return safeCopy(usedUndeclaredArtifacts);
}
@@ -294,29 +309,29 @@ public class ProjectDependencyAnalysis {
return (set == null) ? Collections.emptySet() :
Collections.unmodifiableSet(new LinkedHashSet<>(set));
}
- private static Map<Artifact, Set<String>> safeCopy(Map<Artifact,
Set<String>> origMap) {
+ private static Map<Artifact, Set<DependencyUsage>> safeCopy(Map<Artifact,
Set<DependencyUsage>> origMap) {
if (origMap == null) {
return Collections.emptyMap();
}
- Map<Artifact, Set<String>> map = new HashMap<>();
+ Map<Artifact, Set<DependencyUsage>> map = new HashMap<>();
- for (Map.Entry<Artifact, Set<String>> e : origMap.entrySet()) {
+ for (Map.Entry<Artifact, Set<DependencyUsage>> e : origMap.entrySet())
{
map.put(e.getKey(), Collections.unmodifiableSet(new
LinkedHashSet<>(e.getValue())));
}
return map;
}
- private static Map<Artifact, Set<String>> mapWithKeys(Set<Artifact> keys) {
+ private static Map<Artifact, Set<DependencyUsage>>
mapWithKeys(Set<Artifact> keys) {
if (keys == null) {
return Collections.emptyMap();
}
- Map<Artifact, Set<String>> map = new HashMap<>();
+ Map<Artifact, Set<DependencyUsage>> map = new HashMap<>();
for (Artifact k : keys) {
- map.put(k, Collections.<String>emptySet());
+ map.put(k, Collections.<DependencyUsage>emptySet());
}
return map;
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ASMDependencyAnalyzer.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ASMDependencyAnalyzer.java
index 7b542cd..4e85c7b 100644
---
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ASMDependencyAnalyzer.java
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ASMDependencyAnalyzer.java
@@ -28,6 +28,7 @@ import java.util.Set;
import org.apache.maven.shared.dependency.analyzer.ClassFileVisitorUtils;
import org.apache.maven.shared.dependency.analyzer.ClassesPatterns;
import org.apache.maven.shared.dependency.analyzer.DependencyAnalyzer;
+import org.apache.maven.shared.dependency.analyzer.DependencyUsage;
/**
* ASMDependencyAnalyzer
@@ -39,11 +40,11 @@ import
org.apache.maven.shared.dependency.analyzer.DependencyAnalyzer;
public class ASMDependencyAnalyzer implements DependencyAnalyzer {
@Override
- public Set<String> analyze(URL url, ClassesPatterns excludeClasses) throws
IOException {
+ public Set<DependencyUsage> analyzeUsages(URL url, ClassesPatterns
excludeClasses) throws IOException {
DependencyClassFileVisitor visitor = new
DependencyClassFileVisitor(excludeClasses);
ClassFileVisitorUtils.accept(url, visitor);
- return visitor.getDependencies();
+ return visitor.getDependencyUsages();
}
}
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultAnnotationVisitor.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultAnnotationVisitor.java
index b579273..562637d 100644
---
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultAnnotationVisitor.java
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultAnnotationVisitor.java
@@ -31,34 +31,37 @@ import org.objectweb.asm.Type;
public class DefaultAnnotationVisitor extends AnnotationVisitor {
private final ResultCollector resultCollector;
+ private final String usedByClass;
+
/**
* <p>Constructor for DefaultAnnotationVisitor.</p>
*
* @param resultCollector a {@link
org.apache.maven.shared.dependency.analyzer.asm.ResultCollector} object.
*/
- public DefaultAnnotationVisitor(ResultCollector resultCollector) {
+ public DefaultAnnotationVisitor(ResultCollector resultCollector, String
usedByClass) {
super(Opcodes.ASM9);
this.resultCollector = resultCollector;
+ this.usedByClass = usedByClass;
}
/** {@inheritDoc} */
@Override
public void visit(final String name, final Object value) {
if (value instanceof Type) {
- resultCollector.addType((Type) value);
+ resultCollector.addType(usedByClass, (Type) value);
}
}
/** {@inheritDoc} */
@Override
public void visitEnum(final String name, final String desc, final String
value) {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
}
/** {@inheritDoc} */
@Override
public AnnotationVisitor visitAnnotation(final String name, final String
desc) {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
return this;
}
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultClassVisitor.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultClassVisitor.java
index 2d683e6..fe0291c 100644
---
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultClassVisitor.java
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultClassVisitor.java
@@ -44,6 +44,8 @@ public class DefaultClassVisitor extends ClassVisitor {
private final MethodVisitor methodVisitor;
+ private final String usedByClass;
+
/**
* <p>Constructor for DefaultClassVisitor.</p>
*
@@ -58,13 +60,15 @@ public class DefaultClassVisitor extends ClassVisitor {
AnnotationVisitor annotationVisitor,
FieldVisitor fieldVisitor,
MethodVisitor methodVisitor,
- ResultCollector resultCollector) {
+ ResultCollector resultCollector,
+ String usedByClass) {
super(Opcodes.ASM9);
this.signatureVisitor = signatureVisitor;
this.annotationVisitor = annotationVisitor;
this.fieldVisitor = fieldVisitor;
this.methodVisitor = methodVisitor;
this.resultCollector = resultCollector;
+ this.usedByClass = usedByClass;
}
/**
@@ -86,8 +90,8 @@ public class DefaultClassVisitor extends ClassVisitor {
final String superName,
final String[] interfaces) {
if (signature == null) {
- resultCollector.addName(superName);
- resultCollector.addNames(interfaces);
+ resultCollector.addName(usedByClass, superName);
+ resultCollector.addNames(usedByClass, interfaces);
} else {
addSignature(signature);
}
@@ -96,7 +100,7 @@ public class DefaultClassVisitor extends ClassVisitor {
/** {@inheritDoc} */
@Override
public AnnotationVisitor visitAnnotation(final String desc, final boolean
visible) {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
return annotationVisitor;
}
@@ -106,13 +110,13 @@ public class DefaultClassVisitor extends ClassVisitor {
public FieldVisitor visitField(
final int access, final String name, final String desc, final
String signature, final Object value) {
if (signature == null) {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
} else {
addTypeSignature(signature);
}
if (value instanceof Type) {
- resultCollector.addType((Type) value);
+ resultCollector.addType(usedByClass, (Type) value);
}
return fieldVisitor;
@@ -132,12 +136,12 @@ public class DefaultClassVisitor extends ClassVisitor {
public MethodVisitor visitMethod(
final int access, final String name, final String desc, final
String signature, final String[] exceptions) {
if (signature == null) {
- resultCollector.addMethodDesc(desc);
+ resultCollector.addMethodDesc(usedByClass, desc);
} else {
addSignature(signature);
}
- resultCollector.addNames(exceptions);
+ resultCollector.addNames(usedByClass, exceptions);
return methodVisitor;
}
@@ -145,13 +149,13 @@ public class DefaultClassVisitor extends ClassVisitor {
/** {@inheritDoc} */
@Override
public void visitNestHost(final String nestHost) {
- resultCollector.addName(nestHost);
+ resultCollector.addName(usedByClass, nestHost);
}
/** {@inheritDoc} */
@Override
public void visitNestMember(final String nestMember) {
- resultCollector.addName(nestMember);
+ resultCollector.addName(usedByClass, nestMember);
}
private void addSignature(final String signature) {
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultFieldVisitor.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultFieldVisitor.java
index 6f7e140..2a791b9 100644
---
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultFieldVisitor.java
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultFieldVisitor.java
@@ -33,22 +33,26 @@ public class DefaultFieldVisitor extends FieldVisitor {
private final ResultCollector resultCollector;
+ private final String usedByClass;
+
/**
* <p>Constructor for DefaultFieldVisitor.</p>
*
* @param annotationVisitor a {@link org.objectweb.asm.AnnotationVisitor}
object.
* @param resultCollector a {@link
org.apache.maven.shared.dependency.analyzer.asm.ResultCollector} object.
*/
- public DefaultFieldVisitor(AnnotationVisitor annotationVisitor,
ResultCollector resultCollector) {
+ public DefaultFieldVisitor(
+ AnnotationVisitor annotationVisitor, ResultCollector
resultCollector, String usedByClass) {
super(Opcodes.ASM9);
this.annotationVisitor = annotationVisitor;
this.resultCollector = resultCollector;
+ this.usedByClass = usedByClass;
}
/** {@inheritDoc} */
@Override
public AnnotationVisitor visitAnnotation(final String desc, final boolean
visible) {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
return annotationVisitor;
}
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultMethodVisitor.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultMethodVisitor.java
index d1b8d94..a61bb04 100644
---
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultMethodVisitor.java
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultMethodVisitor.java
@@ -43,6 +43,8 @@ public class DefaultMethodVisitor extends MethodVisitor {
private final ResultCollector resultCollector;
+ private final String usedByClass;
+
/**
* <p>Constructor for DefaultMethodVisitor.</p>
*
@@ -51,17 +53,21 @@ public class DefaultMethodVisitor extends MethodVisitor {
* @param resultCollector a {@link
org.apache.maven.shared.dependency.analyzer.asm.ResultCollector} object.
*/
public DefaultMethodVisitor(
- AnnotationVisitor annotationVisitor, SignatureVisitor
signatureVisitor, ResultCollector resultCollector) {
+ AnnotationVisitor annotationVisitor,
+ SignatureVisitor signatureVisitor,
+ ResultCollector resultCollector,
+ String usedByClass) {
super(Opcodes.ASM9);
this.annotationVisitor = annotationVisitor;
this.signatureVisitor = signatureVisitor;
this.resultCollector = resultCollector;
+ this.usedByClass = usedByClass;
}
/** {@inheritDoc} */
@Override
public AnnotationVisitor visitAnnotation(final String desc, final boolean
visible) {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
return annotationVisitor;
}
@@ -69,7 +75,7 @@ public class DefaultMethodVisitor extends MethodVisitor {
/** {@inheritDoc} */
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath
typePath, String desc, boolean visible) {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
return annotationVisitor;
}
@@ -77,7 +83,7 @@ public class DefaultMethodVisitor extends MethodVisitor {
/** {@inheritDoc} */
@Override
public AnnotationVisitor visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
return annotationVisitor;
}
@@ -86,7 +92,7 @@ public class DefaultMethodVisitor extends MethodVisitor {
@Override
public AnnotationVisitor visitLocalVariableAnnotation(
int typeRef, TypePath typePath, Label[] start, Label[] end, int[]
index, String desc, boolean visible) {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
return annotationVisitor;
}
@@ -95,16 +101,16 @@ public class DefaultMethodVisitor extends MethodVisitor {
@Override
public void visitTypeInsn(final int opcode, final String desc) {
if (desc.charAt(0) == '[') {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
} else {
- resultCollector.addName(desc);
+ resultCollector.addName(usedByClass, desc);
}
}
/** {@inheritDoc} */
@Override
public void visitFieldInsn(final int opcode, final String owner, final
String name, final String desc) {
- resultCollector.addName(owner);
+ resultCollector.addName(usedByClass, owner);
/*
* NOTE: Merely accessing a field does not impose a direct dependency
on its type. For example, the code line
* <code>java.lang.Object var = bean.field;</code> does not directly
depend on the type of the field. A direct
@@ -116,30 +122,32 @@ public class DefaultMethodVisitor extends MethodVisitor {
/** {@inheritDoc} */
@Override
public void visitMethodInsn(int opcode, String owner, String name, String
desc, boolean itf) {
- resultCollector.addName(owner);
+ resultCollector.addName(usedByClass, owner);
}
/** {@inheritDoc} */
@Override
public void visitLdcInsn(final Object cst) {
if (cst instanceof Type) {
- resultCollector.addType((Type) cst);
+ resultCollector.addType(usedByClass, (Type) cst);
}
}
/** {@inheritDoc} */
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
}
/** {@inheritDoc} */
@Override
public void visitTryCatchBlock(final Label start, final Label end, final
Label handler, final String type) {
- resultCollector.addName(type);
+ resultCollector.addName(usedByClass, type);
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
@Override
public void visitLocalVariable(
final String name,
@@ -149,7 +157,7 @@ public class DefaultMethodVisitor extends MethodVisitor {
final Label end,
final int index) {
if (signature == null) {
- resultCollector.addDesc(desc);
+ resultCollector.addDesc(usedByClass, desc);
} else {
addTypeSignature(signature);
}
@@ -167,6 +175,6 @@ public class DefaultMethodVisitor extends MethodVisitor {
Arrays.stream(bootstrapMethodArguments)
.filter(Type.class::isInstance)
.map(Type.class::cast)
- .forEach(resultCollector::addType);
+ .forEach(t -> resultCollector.addType(usedByClass, t));
}
}
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultSignatureVisitor.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultSignatureVisitor.java
index d09bca3..60e7dc6 100644
---
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultSignatureVisitor.java
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultSignatureVisitor.java
@@ -29,26 +29,28 @@ import org.objectweb.asm.signature.SignatureVisitor;
*/
public class DefaultSignatureVisitor extends SignatureVisitor {
private final ResultCollector resultCollector;
+ private final String usedByClass;
/**
* <p>Constructor for DefaultSignatureVisitor.</p>
*
* @param resultCollector a {@link
org.apache.maven.shared.dependency.analyzer.asm.ResultCollector} object.
*/
- public DefaultSignatureVisitor(ResultCollector resultCollector) {
+ public DefaultSignatureVisitor(ResultCollector resultCollector, String
usedByClass) {
super(Opcodes.ASM9);
this.resultCollector = resultCollector;
+ this.usedByClass = usedByClass;
}
/** {@inheritDoc} */
@Override
public void visitClassType(final String name) {
- resultCollector.addName(name);
+ resultCollector.addName(usedByClass, name);
}
/** {@inheritDoc} */
@Override
public void visitInnerClassType(final String name) {
- resultCollector.addName(name);
+ resultCollector.addName(usedByClass, name);
}
}
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyClassFileVisitor.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyClassFileVisitor.java
index 34dac5c..3d16943 100644
---
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyClassFileVisitor.java
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyClassFileVisitor.java
@@ -26,6 +26,7 @@ import java.util.Set;
import org.apache.maven.shared.dependency.analyzer.ClassFileVisitor;
import org.apache.maven.shared.dependency.analyzer.ClassesPatterns;
+import org.apache.maven.shared.dependency.analyzer.DependencyUsage;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
@@ -76,15 +77,16 @@ public class DependencyClassFileVisitor implements
ClassFileVisitor {
final Set<String> constantPoolClassRefs =
ConstantPoolParser.getConstantPoolClassReferences(byteCode);
for (String string : constantPoolClassRefs) {
- resultCollector.addName(string);
+ resultCollector.addName(className, string);
}
- AnnotationVisitor annotationVisitor = new
DefaultAnnotationVisitor(resultCollector);
- SignatureVisitor signatureVisitor = new
DefaultSignatureVisitor(resultCollector);
- FieldVisitor fieldVisitor = new
DefaultFieldVisitor(annotationVisitor, resultCollector);
- MethodVisitor mv = new DefaultMethodVisitor(annotationVisitor,
signatureVisitor, resultCollector);
- ClassVisitor classVisitor =
- new DefaultClassVisitor(signatureVisitor,
annotationVisitor, fieldVisitor, mv, resultCollector);
+ AnnotationVisitor annotationVisitor = new
DefaultAnnotationVisitor(resultCollector, className);
+ SignatureVisitor signatureVisitor = new
DefaultSignatureVisitor(resultCollector, className);
+ FieldVisitor fieldVisitor = new
DefaultFieldVisitor(annotationVisitor, resultCollector, className);
+ MethodVisitor mv =
+ new DefaultMethodVisitor(annotationVisitor,
signatureVisitor, resultCollector, className);
+ ClassVisitor classVisitor = new DefaultClassVisitor(
+ signatureVisitor, annotationVisitor, fieldVisitor, mv,
resultCollector, className);
reader.accept(classVisitor, 0);
} catch (IOException exception) {
@@ -116,4 +118,14 @@ public class DependencyClassFileVisitor implements
ClassFileVisitor {
public Set<String> getDependencies() {
return resultCollector.getDependencies();
}
+
+ /**
+ * <p>getDependencyUsages.</p>
+ *
+ * @return the set of classes referenced by visited class files, paired
with
+ * classes declaring the references.
+ */
+ public Set<DependencyUsage> getDependencyUsages() {
+ return resultCollector.getDependencyUsages();
+ }
}
diff --git
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ResultCollector.java
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ResultCollector.java
index ca9e8ee..65e3937 100644
---
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ResultCollector.java
+++
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ResultCollector.java
@@ -20,7 +20,9 @@ package org.apache.maven.shared.dependency.analyzer.asm;
import java.util.HashSet;
import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.maven.shared.dependency.analyzer.DependencyUsage;
import org.objectweb.asm.Type;
/**
@@ -30,7 +32,7 @@ import org.objectweb.asm.Type;
*/
public class ResultCollector {
- private final Set<String> classes = new HashSet<>();
+ private final Set<DependencyUsage> classUsages = new HashSet<>();
/**
* <p>getDependencies.</p>
@@ -38,7 +40,18 @@ public class ResultCollector {
* @return a {@link java.util.Set} object.
*/
public Set<String> getDependencies() {
- return classes;
+ return getDependencyUsages().stream()
+ .map(DependencyUsage::getDependencyClass)
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * <p>getDependencyUsages.</p>
+ *
+ * @return a {@link java.util.Set} object.
+ */
+ public Set<DependencyUsage> getDependencyUsages() {
+ return classUsages;
}
/**
@@ -46,7 +59,7 @@ public class ResultCollector {
*
* @param name a {@link java.lang.String} object.
*/
- public void addName(String name) {
+ public void addName(final String usedByClass, String name) {
if (name == null) {
return;
}
@@ -65,25 +78,25 @@ public class ResultCollector {
}
// decode internal representation
- add(name.replace('/', '.'));
+ add(usedByClass, name.replace('/', '.'));
}
- void addDesc(final String desc) {
- addType(Type.getType(desc));
+ void addDesc(final String usedByClass, final String desc) {
+ addType(usedByClass, Type.getType(desc));
}
- void addType(final Type t) {
+ void addType(final String usedByClass, final Type t) {
switch (t.getSort()) {
case Type.ARRAY:
- addType(t.getElementType());
+ addType(usedByClass, t.getElementType());
break;
case Type.METHOD:
- addMethodDesc(t.getDescriptor());
+ addMethodDesc(usedByClass, t.getDescriptor());
break;
case Type.OBJECT:
- addName(t.getClassName());
+ addName(usedByClass, t.getClassName());
break;
default:
}
@@ -94,30 +107,30 @@ public class ResultCollector {
*
* @param name a {@link java.lang.String} object.
*/
- public void add(String name) {
+ public void add(final String usedByClass, final String name) {
// inner classes have equivalent compilation requirement as container
class
if (name.indexOf('$') < 0) {
- classes.add(name);
+ classUsages.add(new DependencyUsage(name, usedByClass));
}
}
- void addNames(final String[] names) {
+ void addNames(final String usedByClass, final String[] names) {
if (names == null) {
return;
}
for (String name : names) {
- addName(name);
+ addName(usedByClass, name);
}
}
- void addMethodDesc(final String desc) {
- addType(Type.getReturnType(desc));
+ void addMethodDesc(final String usedByClass, final String desc) {
+ addType(usedByClass, Type.getReturnType(desc));
Type[] types = Type.getArgumentTypes(desc);
for (Type type : types) {
- addType(type);
+ addType(usedByClass, type);
}
}
}
diff --git
a/src/test/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyVisitorTest.java
b/src/test/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyVisitorTest.java
index cad3a2a..7d814e7 100644
---
a/src/test/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyVisitorTest.java
+++
b/src/test/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyVisitorTest.java
@@ -41,13 +41,16 @@ class DependencyVisitorTest {
private DefaultClassVisitor visitor;
private MethodVisitor mv;
+ private String usedByClass = "com.example.MyClass";
+
@BeforeEach
void setUp() {
- AnnotationVisitor annotationVisitor = new
DefaultAnnotationVisitor(resultCollector);
- SignatureVisitor signatureVisitor = new
DefaultSignatureVisitor(resultCollector);
- FieldVisitor fieldVisitor = new DefaultFieldVisitor(annotationVisitor,
resultCollector);
- mv = new DefaultMethodVisitor(annotationVisitor, signatureVisitor,
resultCollector);
- visitor = new DefaultClassVisitor(signatureVisitor, annotationVisitor,
fieldVisitor, mv, resultCollector);
+ AnnotationVisitor annotationVisitor = new
DefaultAnnotationVisitor(resultCollector, usedByClass);
+ SignatureVisitor signatureVisitor = new
DefaultSignatureVisitor(resultCollector, usedByClass);
+ FieldVisitor fieldVisitor = new DefaultFieldVisitor(annotationVisitor,
resultCollector, usedByClass);
+ mv = new DefaultMethodVisitor(annotationVisitor, signatureVisitor,
resultCollector, usedByClass);
+ visitor = new DefaultClassVisitor(
+ signatureVisitor, annotationVisitor, fieldVisitor, mv,
resultCollector, usedByClass);
}
@Test