From 2424dfd70616602f11b85d918117713b1ff6917a Mon Sep 17 00:00:00 2001 From: Joseph Walton Date: Sun, 5 Dec 2021 00:38:47 +1100 Subject: [PATCH 1/4] [MDEP-779] Test detection of used, undeclared dependencies. This is simply a test of the existing functionality. --- .../DefaultProjectDependencyAnalyzerTest.java | 16 ++++++++ .../resources/usedUndeclaredReference/pom.xml | 41 +++++++++++++++++++ .../java/usedUndeclaredReference/Project.java | 25 +++++++++++ 3 files changed, 82 insertions(+) create mode 100644 src/test/resources/usedUndeclaredReference/pom.xml create mode 100644 src/test/resources/usedUndeclaredReference/src/main/java/usedUndeclaredReference/Project.java 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 3c8516a3..1eca62be 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 @@ -421,6 +421,22 @@ public void testJarWithClassInUnnamedPackage() assertEquals( expectedAnalysis, actualAnalysis ); } + @Test + public void testUsedUndeclaredClassReference() + throws TestToolsException, ProjectDependencyAnalyzerException + { + compileProject( "usedUndeclaredReference/pom.xml" ); + + MavenProject project = getProject( "usedUndeclaredReference/pom.xml" ); + + ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project ); + + Artifact xmlApis = createArtifact( "xml-apis", "xml-apis", "jar", "1.0.b2", "compile" ); + Set expectedUsedUndeclaredArtifacts = Collections.singleton( xmlApis ); + + assertEquals( expectedUsedUndeclaredArtifacts, actualAnalysis.getUsedUndeclaredArtifacts() ); + } + // private methods -------------------------------------------------------- private void compileProject( String pomPath ) diff --git a/src/test/resources/usedUndeclaredReference/pom.xml b/src/test/resources/usedUndeclaredReference/pom.xml new file mode 100644 index 00000000..2a8e6520 --- /dev/null +++ b/src/test/resources/usedUndeclaredReference/pom.xml @@ -0,0 +1,41 @@ + + + + + + 4.0.0 + + org.apache.maven.shared.dependency-analyzer.tests + usedUndeclaredReference + 1.0 + jar + + + + dom4j + dom4j + 1.6.1 + + + diff --git a/src/test/resources/usedUndeclaredReference/src/main/java/usedUndeclaredReference/Project.java b/src/test/resources/usedUndeclaredReference/src/main/java/usedUndeclaredReference/Project.java new file mode 100644 index 00000000..5432b405 --- /dev/null +++ b/src/test/resources/usedUndeclaredReference/src/main/java/usedUndeclaredReference/Project.java @@ -0,0 +1,25 @@ +package usedUndeclaredReference; + +/* + * 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. + */ + +public class Project +{ + public static final Class CLASS_REF = org.apache.xmlcommons.Version.class; +} From aeda4f404e49dd8ddff9c89d34aecdbb8bd661ed Mon Sep 17 00:00:00 2001 From: Joseph Walton Date: Sun, 5 Dec 2021 17:34:22 +1100 Subject: [PATCH 2/4] [MDEP-779] Store names along with artifacts for used undeclared artifacts. - Include the names of classes along with the record of used, undeclared artifacts. - Add necessary types to disambiguate constructors in existing tests. --- .../analyzer/ProjectDependencyAnalysis.java | 59 ++++++++++++++++--- .../DefaultProjectDependencyAnalyzerTest.java | 16 ++--- 2 files changed, 60 insertions(+), 15 deletions(-) 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 d75ad4b0..05216949 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,11 @@ import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; +import java.util.Map; import java.util.Set; import org.apache.maven.artifact.Artifact; @@ -39,7 +41,7 @@ public class ProjectDependencyAnalysis private final Set usedDeclaredArtifacts; - private final Set usedUndeclaredArtifacts; + private final Map> usedUndeclaredArtifacts; private final Set unusedDeclaredArtifacts; @@ -50,7 +52,7 @@ public class ProjectDependencyAnalysis */ public ProjectDependencyAnalysis() { - this( null, null, null, null ); + this( null, (Map>) null, null, null ); } /** @@ -63,10 +65,8 @@ public ProjectDependencyAnalysis() 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, Collections.emptySet() ); } /** @@ -80,6 +80,17 @@ public ProjectDependencyAnalysis( Set usedDeclaredArtifacts, Set usedDeclaredArtifacts, Set usedUndeclaredArtifacts, Set unusedDeclaredArtifacts, Set testArtifactsWithNonTestScope ) + { + this( usedDeclaredArtifacts, + mapWithKeys( usedUndeclaredArtifacts ), + unusedDeclaredArtifacts, + testArtifactsWithNonTestScope ); + } + + public ProjectDependencyAnalysis( Set usedDeclaredArtifacts, + Map> usedUndeclaredArtifacts, + Set unusedDeclaredArtifacts, + Set testArtifactsWithNonTestScope ) { this.usedDeclaredArtifacts = safeCopy( usedDeclaredArtifacts ); this.usedUndeclaredArtifacts = safeCopy( usedUndeclaredArtifacts ); @@ -104,7 +115,7 @@ public Set getUsedDeclaredArtifacts() */ public Set getUsedUndeclaredArtifacts() { - return safeCopy( usedUndeclaredArtifacts ); + return safeCopy( usedUndeclaredArtifacts.keySet() ); } /** @@ -297,4 +308,38 @@ private Set safeCopy( Set set ) { return ( set == null ) ? Collections.emptySet() : Collections.unmodifiableSet( new LinkedHashSet<>( set ) ); } + + private static Map> safeCopy( Map> origMap ) + { + if ( origMap == null ) + { + return Collections.emptyMap(); + } + + Map> map = new HashMap<>(); + + for ( Map.Entry> e : origMap.entrySet() ) + { + map.put( e.getKey(), Collections.unmodifiableSet( new LinkedHashSet<>( e.getValue() ) ) ); + } + + return map; + } + + private static Map> mapWithKeys( Set keys ) + { + if ( keys == null ) + { + return Collections.emptyMap(); + } + + Map> map = new HashMap<>(); + + for ( Artifact k : keys ) + { + map.put( k, Collections.emptySet() ); + } + + return map; + } } 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 1eca62be..8b0f8918 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 @@ -182,7 +182,7 @@ public void testJarWithCompileDependency() "jarWithCompileDependency1", "jar", "1.0", "compile" ); Artifact guava = createArtifact( "com.google.guava", "guava", "jar", "30.1.1-android", "compile" ); Set usedDeclaredArtifacts = new HashSet<>( Arrays.asList( project1, guava ) ); - ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null, + ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set) null, null, null ); assertEquals( expectedAnalysis, actualAnalysis ); @@ -238,7 +238,7 @@ public void testJarWithTestDependency() Artifact junit = createArtifact( "junit", "junit", "jar", "3.8.1", "test" ); Set usedDeclaredArtifacts = new HashSet<>( Arrays.asList( project1, junit ) ); - ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null, null ); + ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set) null, null, null ); assertEquals( expectedAnalysis, actualAnalysis ); } @@ -256,7 +256,7 @@ public void testJarWithXmlTransitiveDependency() Artifact jdom = createArtifact( "dom4j", "dom4j", "jar", "1.6.1", "compile" ); Set usedDeclaredArtifacts = Collections.singleton( jdom ); - ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null, + ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set) null, null, null ); // MSHARED-47: usedUndeclaredArtifacts=[xml-apis:xml-apis:jar:1.0.b2:compile] @@ -279,7 +279,7 @@ public void testJarWithCompileScopedTestDependency() Set usedDeclaredArtifacts = new HashSet<>( Arrays.asList( artifact1, junit ) ); Set nonTestScopedTestArtifacts = Collections.singleton( junit ); - ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null, + ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set) null, null, nonTestScopedTestArtifacts ); assertEquals( expectedAnalysis, actualAnalysis ); @@ -300,7 +300,7 @@ public void testJarWithRuntimeScopedTestDependency() throws TestToolsException, Artifact junit = createArtifact( "junit", "junit", "jar", "3.8.1", "runtime" ); Set usedDeclaredArtifacts = new HashSet<>( Arrays.asList( artifact1, junit ) ); - ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null, + ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set) null, null, null ); assertEquals( expectedAnalysis, actualAnalysis ); @@ -331,7 +331,7 @@ public void testMultimoduleProject() Artifact junit = createArtifact( "org.apache.maven.its.dependency", "test-module1", "jar", "1.0", "compile" ); Set usedDeclaredArtifacts = Collections.singleton( junit ); - ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, null, null, + ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set) null, null, null ); assertEquals( expectedAnalysis, actualAnalysis ); @@ -353,7 +353,7 @@ public void testTypeUseAnnotationDependency() Artifact annotation = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests", "typeUseAnnotationDependencyAnnotation", "jar", "1.0", "compile" ); Set usedDeclaredArtifacts = Collections.singleton( annotation ); - ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(usedDeclaredArtifacts, null, null, + ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(usedDeclaredArtifacts, (Set) null, null, null ); assertEquals( expectedAnalysis, actualAnalysis ); @@ -375,7 +375,7 @@ public void testTypeUseAnnotationDependencyOnLocalVariable() Artifact annotation = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests", "typeUseAnnotationDependencyAnnotation", "jar", "1.0", "compile" ); Set usedDeclaredArtifacts = Collections.singleton( annotation ); - ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(usedDeclaredArtifacts, null, null, + ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(usedDeclaredArtifacts, (Set) null, null, null); assertEquals( expectedAnalysis, actualAnalysis ); From c3185c2512b1ecaa7874d184fefac844cc661394 Mon Sep 17 00:00:00 2001 From: Joseph Walton Date: Sun, 5 Dec 2021 17:35:12 +1100 Subject: [PATCH 3/4] [MDEP-779] Include referenced classes in the used undeclared results. --- .../DefaultProjectDependencyAnalyzer.java | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 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 363b9f72..6e704c4f 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,6 +24,7 @@ import java.net.URL; import java.util.Collections; import java.util.Enumeration; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -73,24 +74,26 @@ public ProjectDependencyAnalysis analyze( MavenProject project ) Set declaredArtifacts = buildDeclaredArtifacts( project ); - Set usedArtifacts = buildUsedArtifacts( artifactClassMap, dependencyClasses ); - Set mainUsedArtifacts = buildUsedArtifacts( artifactClassMap, mainDependencyClasses ); - - Set testArtifacts = buildUsedArtifacts( artifactClassMap, testOnlyDependencyClasses ); + Map> usedArtifacts = buildUsedArtifacts( artifactClassMap, dependencyClasses ); + Set mainUsedArtifacts = buildUsedArtifacts( artifactClassMap, mainDependencyClasses ).keySet(); + + Set testArtifacts = buildUsedArtifacts( artifactClassMap, testOnlyDependencyClasses ).keySet(); Set testOnlyArtifacts = removeAll( testArtifacts, mainUsedArtifacts ); - + Set usedDeclaredArtifacts = new LinkedHashSet<>( declaredArtifacts ); - usedDeclaredArtifacts.retainAll( usedArtifacts ); + usedDeclaredArtifacts.retainAll( usedArtifacts.keySet() ); - Set usedUndeclaredArtifacts = new LinkedHashSet<>( usedArtifacts ); - usedUndeclaredArtifacts = removeAll( usedUndeclaredArtifacts, declaredArtifacts ); + Map> usedUndeclaredArtifactsWithClasses = new LinkedHashMap<>( usedArtifacts ); + Set usedUndeclaredArtifacts = removeAll( + usedUndeclaredArtifactsWithClasses.keySet(), declaredArtifacts ); + usedUndeclaredArtifactsWithClasses.keySet().retainAll( usedUndeclaredArtifacts ); Set unusedDeclaredArtifacts = new LinkedHashSet<>( declaredArtifacts ); - unusedDeclaredArtifacts = removeAll( unusedDeclaredArtifacts, usedArtifacts ); + unusedDeclaredArtifacts = removeAll( unusedDeclaredArtifacts, usedArtifacts.keySet() ); Set testArtifactsWithNonTestScope = getTestArtifactsWithNonTestScope( testOnlyArtifacts ); - return new ProjectDependencyAnalysis( usedDeclaredArtifacts, usedUndeclaredArtifacts, + return new ProjectDependencyAnalysis( usedDeclaredArtifacts, usedUndeclaredArtifactsWithClasses, unusedDeclaredArtifacts, testArtifactsWithNonTestScope ); } catch ( IOException exception ) @@ -259,10 +262,10 @@ private Set buildDeclaredArtifacts( MavenProject project ) return declaredArtifacts; } - private Set buildUsedArtifacts( Map> artifactClassMap, + private Map> buildUsedArtifacts( Map> artifactClassMap, Set dependencyClasses ) { - Set usedArtifacts = new HashSet<>(); + Map> usedArtifacts = new HashMap<>(); for ( String className : dependencyClasses ) { @@ -270,7 +273,13 @@ private Set buildUsedArtifacts( Map> artifactCla if ( artifact != null ) { - usedArtifacts.add( artifact ); + Set classesFromArtifact = usedArtifacts.get( artifact ); + if ( classesFromArtifact == null ) + { + classesFromArtifact = new HashSet(); + usedArtifacts.put( artifact, classesFromArtifact ); + } + classesFromArtifact.add( className ); } } From a5fb9b61df0b78d62eea9107596eb733a1076ff3 Mon Sep 17 00:00:00 2001 From: Joseph Walton Date: Sun, 5 Dec 2021 00:51:10 +1100 Subject: [PATCH 4/4] [MDEP-779] Test that classes are returned. Add testing for specific class names to the case for used, undeclared dependencies. --- .../dependency/analyzer/ProjectDependencyAnalysis.java | 10 ++++++++++ .../analyzer/DefaultProjectDependencyAnalyzerTest.java | 6 ++++++ 2 files changed, 16 insertions(+) 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 05216949..0be4ffd3 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 @@ -118,6 +118,16 @@ public Set getUsedUndeclaredArtifacts() return safeCopy( usedUndeclaredArtifacts.keySet() ); } + /** + * Returns artifacts used but not declared. + * + * @return artifacts used but not declared + */ + public Map> getUsedUndeclaredArtifactsWithClasses() + { + return safeCopy( usedUndeclaredArtifacts ); + } + /** * Returns artifacts declared but not used. * 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 8b0f8918..097837d1 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 @@ -41,6 +41,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.Set; @@ -435,6 +436,11 @@ public void testUsedUndeclaredClassReference() Set expectedUsedUndeclaredArtifacts = Collections.singleton( xmlApis ); assertEquals( expectedUsedUndeclaredArtifacts, actualAnalysis.getUsedUndeclaredArtifacts() ); + + Map> expectedUsedUndeclaredArtifactsWithClasses = + Collections.singletonMap(xmlApis, Collections.singleton("org.apache.xmlcommons.Version") ); + + assertEquals( expectedUsedUndeclaredArtifactsWithClasses, actualAnalysis.getUsedUndeclaredArtifactsWithClasses() ); } // private methods --------------------------------------------------------