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 7b05372a..8c85d85d 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 @@ -24,10 +24,13 @@ import java.net.URL; import java.util.Collections; import java.util.Enumeration; +import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -71,24 +74,25 @@ public ProjectDependencyAnalysis analyze( MavenProject project ) { Map> artifactClassMap = buildArtifactClassMap( project ); - Set dependencyClasses = buildDependencyClasses( project ); + Set dependencyUsages = buildDependencyUsages( project ); Set testOnlyDependencyClasses = buildTestDependencyClasses( project ); Set declaredArtifacts = buildDeclaredArtifacts( project ); - Set usedArtifacts = buildUsedArtifacts( artifactClassMap, dependencyClasses ); + Map> usedArtifacts = buildArtifactToUsageMap( artifactClassMap, + dependencyUsages ); Set testOnlyArtifacts = buildUsedArtifacts( artifactClassMap, testOnlyDependencyClasses ); - Set usedDeclaredArtifacts = new LinkedHashSet( declaredArtifacts ); - usedDeclaredArtifacts.retainAll( usedArtifacts ); + Map> usedDeclaredArtifacts = buildMutableCopy( usedArtifacts ); + usedDeclaredArtifacts.keySet().retainAll( declaredArtifacts ); - Set usedUndeclaredArtifacts = new LinkedHashSet( usedArtifacts ); - usedUndeclaredArtifacts = removeAll( usedUndeclaredArtifacts, declaredArtifacts ); + Map> usedUndeclaredArtifacts = buildMutableCopy( usedArtifacts ); + removeAll( usedUndeclaredArtifacts.keySet(), declaredArtifacts ); Set unusedDeclaredArtifacts = new LinkedHashSet( declaredArtifacts ); - unusedDeclaredArtifacts = removeAll( unusedDeclaredArtifacts, usedArtifacts ); + removeAll( unusedDeclaredArtifacts, usedArtifacts.keySet() ); Set testArtifactsWithNonTestScope = getTestArtifactsWithNonTestScope( testOnlyArtifacts ); @@ -107,32 +111,22 @@ public ProjectDependencyAnalysis analyze( MavenProject project ) * * @param start initial set * @param remove set to exclude - * @return set with remove excluded */ - private Set removeAll( Set start, Set remove ) + private void removeAll( Set start, Set remove ) { - Set results = new LinkedHashSet( start.size() ); - - for ( Artifact artifact : start ) + for ( Iterator iterator = start.iterator(); iterator.hasNext(); ) { - boolean found = false; + Artifact artifact = iterator.next(); for ( Artifact artifact2 : remove ) { if ( artifact.getDependencyConflictId().equals( artifact2.getDependencyConflictId() ) ) { - found = true; + iterator.remove(); break; } } - - if ( !found ) - { - results.add( artifact ); - } } - - return results; } private Set getTestArtifactsWithNonTestScope( Set testOnlyArtifacts ) @@ -217,10 +211,16 @@ private Set buildTestDependencyClasses( MavenProject project ) throws IO Set testOnlyDependencyClasses = new HashSet<>(); String outputDirectory = project.getBuild().getOutputDirectory(); - nonTestDependencyClasses.addAll( buildDependencyClasses( outputDirectory ) ); + for ( DependencyUsage nonTestUsage : buildDependencyUsages( outputDirectory ) ) + { + nonTestDependencyClasses.add( nonTestUsage.getDependencyClass() ); + } String testOutputDirectory = project.getBuild().getTestOutputDirectory(); - testDependencyClasses.addAll( buildDependencyClasses( testOutputDirectory ) ); + for ( DependencyUsage testUsage : buildDependencyUsages( testOutputDirectory ) ) + { + testDependencyClasses.add( testUsage.getDependencyClass() ); + } for ( String testString : testDependencyClasses ) { @@ -233,26 +233,26 @@ private Set buildTestDependencyClasses( MavenProject project ) throws IO return testOnlyDependencyClasses; } - private Set buildDependencyClasses( MavenProject project ) + private Set buildDependencyUsages( MavenProject project ) throws IOException { - Set dependencyClasses = new HashSet(); + Set dependencyUsages = new HashSet(); String outputDirectory = project.getBuild().getOutputDirectory(); - dependencyClasses.addAll( buildDependencyClasses( outputDirectory ) ); + dependencyUsages.addAll( buildDependencyUsages( outputDirectory ) ); String testOutputDirectory = project.getBuild().getTestOutputDirectory(); - dependencyClasses.addAll( buildDependencyClasses( testOutputDirectory ) ); + dependencyUsages.addAll( buildDependencyUsages( testOutputDirectory ) ); - return dependencyClasses; + return dependencyUsages; } - private Set buildDependencyClasses( String path ) + private Set buildDependencyUsages( String path ) throws IOException { URL url = new File( path ).toURI().toURL(); - return dependencyAnalyzer.analyze( url ); + return dependencyAnalyzer.analyzeWithUsages( url ); } private Set buildDeclaredArtifacts( MavenProject project ) @@ -286,6 +286,31 @@ private Set buildUsedArtifacts( Map> artifactCla return usedArtifacts; } + private Map> buildArtifactToUsageMap( Map> artifactClassMap, + Set dependencyUsages ) + { + Map> dependencyClassToUsages = buildDependencyClassToUsageMap( dependencyUsages ); + + Map> artifactToUsages = new HashMap>(); + + for ( Entry> entry : dependencyClassToUsages.entrySet() ) + { + Artifact artifact = findArtifactForClassName( artifactClassMap, entry.getKey() ); + + if ( artifact != null ) + { + if ( !artifactToUsages.containsKey( artifact ) ) + { + artifactToUsages.put( artifact, new HashSet() ); + } + + artifactToUsages.get( artifact ).addAll( entry.getValue() ); + } + } + + return artifactToUsages; + } + private Artifact findArtifactForClassName( Map> artifactClassMap, String className ) { for ( Map.Entry> entry : artifactClassMap.entrySet() ) @@ -298,4 +323,35 @@ private Artifact findArtifactForClassName( Map> artifactCl return null; } + + private Map> buildDependencyClassToUsageMap( Set dependencyUsages ) + { + Map> dependencyClassToUsages = new HashMap>(); + + for ( DependencyUsage dependencyUsage : dependencyUsages ) + { + String dependencyClass = dependencyUsage.getDependencyClass(); + + if ( !dependencyClassToUsages.containsKey( dependencyClass ) ) + { + dependencyClassToUsages.put( dependencyClass, new HashSet() ); + } + + dependencyClassToUsages.get( dependencyClass ).add( dependencyUsage ); + } + + return dependencyClassToUsages; + } + + private Map> buildMutableCopy( Map> map ) + { + Map> copy = new LinkedHashMap>(); + + for ( Entry> entry : map.entrySet() ) + { + copy.put( entry.getKey(), new LinkedHashSet( entry.getValue() ) ); + } + + return copy; + } } 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 5de91e97..542ba0b7 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 @@ -39,4 +39,7 @@ public interface DependencyAnalyzer Set analyze( URL url ) throws IOException; + + Set analyzeWithUsages( URL url ) + 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 00000000..8b582e25 --- /dev/null +++ b/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyUsage.java @@ -0,0 +1,105 @@ +package org.apache.maven.shared.dependency.analyzer; + +/* + * 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. + */ + +import java.util.Objects; + +/** + * Usage of a dependency class by a project class. + * + * @author Jonathan Haber + */ +public final class DependencyUsage +{ + // fields ----------------------------------------------------------------- + + private final String dependencyClass; + + private final String usedBy; + + // constructors ----------------------------------------------------------- + + public DependencyUsage( String dependencyClass, String usedBy ) + { + this.dependencyClass = Objects.requireNonNull( dependencyClass, "dependencyClass" ); + this.usedBy = Objects.requireNonNull( usedBy, "usedBy" ); + } + + // public methods --------------------------------------------------------- + + + public String getDependencyClass() + { + return dependencyClass; + } + + public String getUsedBy() + { + return usedBy; + } + + // Object methods --------------------------------------------------------- + + /* + * @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 ecfc6d13..b2806bda 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 @@ -21,9 +21,13 @@ import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import org.apache.maven.artifact.Artifact; @@ -38,9 +42,9 @@ public class ProjectDependencyAnalysis { // fields ----------------------------------------------------------------- - private final Set usedDeclaredArtifacts; + private final Map> usedDeclaredArtifacts; - private final Set usedUndeclaredArtifacts; + private final Map> usedUndeclaredArtifacts; private final Set unusedDeclaredArtifacts; @@ -50,22 +54,31 @@ public class ProjectDependencyAnalysis public ProjectDependencyAnalysis() { - this( null, null, null, null ); + this( ( Set ) null, null, null, null ); } // constructor to maintain compatibility with old API public ProjectDependencyAnalysis( Set usedDeclaredArtifacts, Set usedUndeclaredArtifacts, Set unusedDeclaredArtifacts ) { - this.usedDeclaredArtifacts = safeCopy( usedDeclaredArtifacts ); - this.usedUndeclaredArtifacts = safeCopy( usedUndeclaredArtifacts ); - this.unusedDeclaredArtifacts = safeCopy( unusedDeclaredArtifacts ); - this.testArtifactsWithNonTestScope = new HashSet<>(); + this( usedDeclaredArtifacts, usedUndeclaredArtifacts, unusedDeclaredArtifacts, new HashSet() ); } + // constructor to maintain compatibility with old API public ProjectDependencyAnalysis( Set usedDeclaredArtifacts, Set usedUndeclaredArtifacts, Set unusedDeclaredArtifacts, Set testArtifactsWithNonTestScope ) + { + this( toMap( usedDeclaredArtifacts ), + toMap( usedUndeclaredArtifacts ), + unusedDeclaredArtifacts, + testArtifactsWithNonTestScope ); + } + + public ProjectDependencyAnalysis( Map> usedDeclaredArtifacts, + Map> usedUndeclaredArtifacts, + Set unusedDeclaredArtifacts, + Set testArtifactsWithNonTestScope ) { this.usedDeclaredArtifacts = safeCopy( usedDeclaredArtifacts ); this.usedUndeclaredArtifacts = safeCopy( usedUndeclaredArtifacts ); @@ -80,6 +93,14 @@ public ProjectDependencyAnalysis( Set usedDeclaredArtifacts, Set getUsedDeclaredArtifacts() + { + return safeCopy( usedDeclaredArtifacts.keySet() ); + } + + /** + * Used and declared artifacts mapped to usages. + */ + public Map> getUsedDeclaredArtifactToUsageMap() { return safeCopy( usedDeclaredArtifacts ); } @@ -89,6 +110,14 @@ public Set getUsedDeclaredArtifacts() * @return {@link Artifact} */ public Set getUsedUndeclaredArtifacts() + { + return safeCopy( usedUndeclaredArtifacts.keySet() ); + } + + /** + * Used but not declared artifacts mapped to usages. + */ + public Map> getUsedUndeclaredArtifactToUsageMap() { return safeCopy( usedUndeclaredArtifacts ); } @@ -150,7 +179,9 @@ public ProjectDependencyAnalysis forceDeclaredDependenciesUsage( String[] forceU Set forced = new HashSet( Arrays.asList( forceUsedDependencies ) ); Set forcedUnusedDeclared = new HashSet( unusedDeclaredArtifacts ); - Set forcedUsedDeclared = new HashSet( usedDeclaredArtifacts ); + Map> forcedUsedDeclared = new HashMap>( + usedDeclaredArtifacts + ); for ( Iterator iter = forcedUnusedDeclared.iterator(); iter.hasNext(); ) { @@ -160,7 +191,10 @@ public ProjectDependencyAnalysis forceDeclaredDependenciesUsage( String[] forceU { // ok, change artifact status from unused-declared to used-declared iter.remove(); - forcedUsedDeclared.add( artifact ); + if ( !forcedUsedDeclared.containsKey( artifact ) ) + { + forcedUsedDeclared.put( artifact, Collections.emptySet() ); + } } } @@ -168,7 +202,7 @@ public ProjectDependencyAnalysis forceDeclaredDependenciesUsage( String[] forceU { // trying to force dependencies as used-declared which were not declared or already detected as used Set used = new HashSet(); - for ( Artifact artifact : usedDeclaredArtifacts ) + for ( Artifact artifact : usedDeclaredArtifacts.keySet() ) { String id = artifact.getGroupId() + ':' + artifact.getArtifactId(); if ( forced.remove( id ) ) @@ -282,9 +316,40 @@ public String toString() // private methods -------------------------------------------------------- - private Set safeCopy( Set set ) + private Set safeCopy( Set set ) { - return ( set == null ) ? Collections.emptySet() - : Collections.unmodifiableSet( new LinkedHashSet( set ) ); + return ( set == null ) ? Collections.emptySet() + : Collections.unmodifiableSet( new LinkedHashSet( set ) ); + } + + private Map> safeCopy( Map> map ) + { + Map> copy = new LinkedHashMap>(); + + for ( Entry> entry : map.entrySet() ) + { + copy.put( entry.getKey(), safeCopy( entry.getValue() ) ); + } + + return Collections.unmodifiableMap( copy ); + } + + private static Map> toMap( Set set ) + { + if ( set == null ) + { + return Collections.>emptyMap(); + } + else + { + Map> map = new HashMap>(); + + for ( Artifact artifact : set ) + { + map.put( artifact, Collections.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 facad096..c36aa853 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 @@ -25,6 +25,7 @@ import org.apache.maven.shared.dependency.analyzer.ClassFileVisitorUtils; import org.apache.maven.shared.dependency.analyzer.DependencyAnalyzer; +import org.apache.maven.shared.dependency.analyzer.DependencyUsage; import org.codehaus.plexus.component.annotations.Component; /** @@ -51,4 +52,17 @@ public Set analyze( URL url ) return visitor.getDependencies(); } + + /* + * @see org.apache.maven.shared.dependency.analyzer.DependencyAnalyzer#analyze(java.net.URL) + */ + public Set analyzeWithUsages( URL url ) + throws IOException + { + DependencyClassFileVisitor visitor = new DependencyClassFileVisitor(); + + ClassFileVisitorUtils.accept( url, visitor ); + + return visitor.getDependencyUsages(); + } } 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 e0b41b0a..eba2d935 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 @@ -19,8 +19,14 @@ * under the License. */ +import java.io.IOException; +import java.io.InputStream; +import java.util.HashSet; +import java.util.Set; + import org.apache.commons.io.IOUtils; import org.apache.maven.shared.dependency.analyzer.ClassFileVisitor; +import org.apache.maven.shared.dependency.analyzer.DependencyUsage; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -28,10 +34,6 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.signature.SignatureVisitor; -import java.io.IOException; -import java.io.InputStream; -import java.util.Set; - /** * Computes the set of classes referenced by visited class files, using * DependencyVisitor. @@ -45,7 +47,9 @@ public class DependencyClassFileVisitor { // fields ----------------------------------------------------------------- - private final ResultCollector resultCollector = new ResultCollector(); + private final Set dependencies = new HashSet(); + + private final Set dependencyUsages = new HashSet(); // constructors ----------------------------------------------------------- @@ -61,6 +65,7 @@ public DependencyClassFileVisitor() */ public void visitClass( String className, InputStream in ) { + ResultCollector resultCollector = new ResultCollector(); try { byte[] byteCode = IOUtils.toByteArray( in ); @@ -91,6 +96,12 @@ public void visitClass( String className, InputStream in ) // this happens when the class isn't valid. System.out.println( "Unable to process: " + className ); } + + for ( String dependencyClass : resultCollector.getDependencies() ) + { + dependencies.add( dependencyClass ); + dependencyUsages.add( new DependencyUsage( dependencyClass, className ) ); + } } // public methods --------------------------------------------------------- @@ -100,6 +111,14 @@ public void visitClass( String className, InputStream in ) */ public Set getDependencies() { - return resultCollector.getDependencies(); + return dependencies; + } + + /** + * @return the set of dependency usages for visited class files + */ + public Set getDependencyUsages() + { + return dependencyUsages; } } diff --git a/src/test/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzerTest.java b/src/test/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzerTest.java index 807be0fd..65a85526 100644 --- a/src/test/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzerTest.java +++ b/src/test/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzerTest.java @@ -3,8 +3,10 @@ import java.io.File; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.Set; @@ -102,6 +104,8 @@ public void testPom() ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(); assertEquals( expectedAnalysis, actualAnalysis ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedDeclaredArtifactToUsageMap() ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedUndeclaredArtifactToUsageMap() ); } public void testJarWithNoDependencies() @@ -116,6 +120,8 @@ public void testJarWithNoDependencies() ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(); assertEquals( expectedAnalysis, actualAnalysis ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedDeclaredArtifactToUsageMap() ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedUndeclaredArtifactToUsageMap() ); } public void testJava8methodRefs() @@ -142,6 +148,19 @@ public void testJava8methodRefs() new HashSet() ); assertEquals( expectedAnalysis, actualAnalysis ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedUndeclaredArtifactToUsageMap() ); + + Map> actualDependencyUsageMap = + actualAnalysis.getUsedDeclaredArtifactToUsageMap(); + + Map> expectedDependencyUsageMap = + new HashMap>(); + expectedDependencyUsageMap.put( project1, createDependencyUsage( + "org.apache.commons.io.FileUtils", "inlinedStaticReference.Project" ) ); + expectedDependencyUsageMap.put( project2, createDependencyUsage( + "org.apache.commons.lang.CharUtils", "inlinedStaticReference.Project" ) ); + + assertEquals( expectedDependencyUsageMap, actualDependencyUsageMap ); } public void testInlinedStaticReference() @@ -167,6 +186,17 @@ public void testInlinedStaticReference() new HashSet() ); assertEquals( expectedAnalysis, actualAnalysis ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedUndeclaredArtifactToUsageMap() ); + + Map> actualDependencyUsageMap = + actualAnalysis.getUsedDeclaredArtifactToUsageMap(); + + Map> expectedDependencyUsageMap = Collections.singletonMap( + project1, + createDependencyUsage( + "org.dom4j.Node", "inlinedStaticReference.Project" ) ); + + assertEquals( expectedDependencyUsageMap, actualDependencyUsageMap ); } public void testJarWithCompileDependency() @@ -192,6 +222,17 @@ public void testJarWithCompileDependency() null ); assertEquals( expectedAnalysis, actualAnalysis ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedUndeclaredArtifactToUsageMap() ); + + Map> actualDependencyUsageMap = + actualAnalysis.getUsedDeclaredArtifactToUsageMap(); + + Map> expectedDependencyUsageMap = Collections.singletonMap( + project1, + createDependencyUsage( + "jarWithCompileDependency.project1.Project1", "jarWithCompileDependency.project2.Project2" ) ); + + assertEquals( expectedDependencyUsageMap, actualDependencyUsageMap ); } public void testForceDeclaredDependenciesUsage() @@ -257,6 +298,22 @@ public void testJarWithTestDependency() } assertEquals( expectedAnalysis, actualAnalysis ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedUndeclaredArtifactToUsageMap() ); + + Map> actualDependencyUsageMap = + actualAnalysis.getUsedDeclaredArtifactToUsageMap(); + + Map> expectedDependencyUsageMap = + new HashMap>(); + expectedDependencyUsageMap.put( project1, createDependencyUsage( + "jarWithTestDependency.project1.Project1", "jarWithTestDependency.project2.Project2" ) ); + if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) ) + { + expectedDependencyUsageMap.put( junit, createDependencyUsage( + "junit.runner.TestRunListener", "jarWithTestDependency.project2.Project2" ) ); + } + + assertEquals( expectedDependencyUsageMap, actualDependencyUsageMap ); } public void testJarWithXmlTransitiveDependency() @@ -309,6 +366,22 @@ public void testJarWithCompileScopedTestDependency() } assertEquals( expectedAnalysis, actualAnalysis ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedUndeclaredArtifactToUsageMap() ); + + Map> actualDependencyUsageMap = + actualAnalysis.getUsedDeclaredArtifactToUsageMap(); + + Map> expectedDependencyUsageMap = + new HashMap>(); + expectedDependencyUsageMap.put( artifact1, createDependencyUsage( + "jarWithTestDependency.project1.Project1", "jarWithTestDependency.project2.Project2" ) ); + if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) ) + { + expectedDependencyUsageMap.put( junit, createDependencyUsage( + "junit.runner.TestRunListener", "jarWithTestDependency.project2.Project2" ) ); + } + + assertEquals( expectedDependencyUsageMap, actualDependencyUsageMap ); } public void testJarWithRuntimeScopedTestDependency() throws TestToolsException, ProjectDependencyAnalyzerException @@ -341,6 +414,22 @@ public void testJarWithRuntimeScopedTestDependency() throws TestToolsException, } assertEquals( expectedAnalysis, actualAnalysis ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedUndeclaredArtifactToUsageMap() ); + + Map> actualDependencyUsageMap = + actualAnalysis.getUsedDeclaredArtifactToUsageMap(); + + Map> expectedDependencyUsageMap = + new HashMap>(); + expectedDependencyUsageMap.put( artifact1, createDependencyUsage( + "jarWithTestDependency.project1.Project1", "jarWithTestDependency.project2.Project2" ) ); + if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) ) + { + expectedDependencyUsageMap.put( junit, createDependencyUsage( + "junit.runner.TestRunListener", "jarWithTestDependency.project2.Project2" ) ); + } + + assertEquals( expectedDependencyUsageMap, actualDependencyUsageMap ); } public void testMultimoduleProject() @@ -364,13 +453,23 @@ public void testMultimoduleProject() ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project ); - Artifact junit = createArtifact( "org.apache.maven.its.dependency", "test-module1", "jar", "1.0", "compile" ); - Set usedDeclaredArtifacts = Collections.singleton( junit ); + Artifact testArtifact = createArtifact( "org.apache.maven.its.dependency", "test-module1", "jar", "1.0", "compile" ); + Set usedDeclaredArtifacts = Collections.singleton( testArtifact ); ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null, null ); assertEquals( expectedAnalysis, actualAnalysis ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedUndeclaredArtifactToUsageMap() ); + + Map> actualDependencyUsageMap = + actualAnalysis.getUsedDeclaredArtifactToUsageMap(); + + Map> expectedDependencyUsageMap = Collections.singletonMap( + testArtifact, + createDependencyUsage("foo.Main", "bar.Main" ) ); + + assertEquals( expectedDependencyUsageMap, actualDependencyUsageMap ); } public void testTypeUseAnnotationDependency() @@ -398,6 +497,17 @@ public void testTypeUseAnnotationDependency() null ); assertEquals( expectedAnalysis, actualAnalysis ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedUndeclaredArtifactToUsageMap() ); + + Map> actualDependencyUsageMap = + actualAnalysis.getUsedDeclaredArtifactToUsageMap(); + + Map> expectedDependencyUsageMap = Collections.singletonMap( + annotation, + createDependencyUsage( + "typeUseAnnotationDependency.annotation.Annotation", "typeUseAnnotationDependency.usage.Usage" ) ); + + assertEquals( expectedDependencyUsageMap, actualDependencyUsageMap ); } public void testTypeUseAnnotationDependencyOnLocalVariable() @@ -425,6 +535,18 @@ public void testTypeUseAnnotationDependencyOnLocalVariable() null); assertEquals( expectedAnalysis, actualAnalysis ); + assertEquals( Collections.emptyMap(), actualAnalysis.getUsedUndeclaredArtifactToUsageMap() ); + + Map> actualDependencyUsageMap = + actualAnalysis.getUsedDeclaredArtifactToUsageMap(); + + Map> expectedDependencyUsageMap = Collections.singletonMap( + annotation, + createDependencyUsage( + "typeUseAnnotationDependency.annotation.Annotation", + "typeUseAnnotationDependency.usageLocalVar.UsageLocalVar" ) ); + + assertEquals( expectedDependencyUsageMap, actualDependencyUsageMap ); } // private methods -------------------------------------------------------- @@ -477,4 +599,9 @@ private Artifact createArtifact( String groupId, String artifactId, String type, return new DefaultArtifact( groupId, artifactId, versionRange, scope, type, null, handler ); } + + private Set createDependencyUsage( String dependencyClass, String usedBy ) + { + return Collections.singleton( new DependencyUsage( dependencyClass, usedBy ) ); + } } diff --git a/src/test/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysisTest.java b/src/test/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysisTest.java index 8f3d7ae1..42bbecd4 100644 --- a/src/test/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysisTest.java +++ b/src/test/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysisTest.java @@ -19,7 +19,9 @@ * under the License. */ +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import org.apache.maven.artifact.Artifact; @@ -41,7 +43,9 @@ public class ProjectDependencyAnalysisTest public void testConstructor() { Set usedDeclaredArtifacts = new HashSet(); + Map> usedDeclaredArtifactToUsageMap = new HashMap>(); Set usedUndeclaredArtifacts = new HashSet(); + Map> usedUndeclaredArtifactToUsageMap = new HashMap>(); Set unusedDeclaredArtifacts = new HashSet(); Set testArtifactsWithNonTestScope = new HashSet(); @@ -50,7 +54,9 @@ public void testConstructor() testArtifactsWithNonTestScope); assertEquals( usedDeclaredArtifacts, analysis.getUsedDeclaredArtifacts() ); + assertEquals( usedDeclaredArtifactToUsageMap, analysis.getUsedDeclaredArtifactToUsageMap() ); assertEquals( usedUndeclaredArtifacts, analysis.getUsedUndeclaredArtifacts() ); + assertEquals( usedUndeclaredArtifactToUsageMap, analysis.getUsedUndeclaredArtifactToUsageMap() ); assertEquals( unusedDeclaredArtifacts, analysis.getUnusedDeclaredArtifacts() ); } }