All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.maven.shared.dependency.analyzer.DefaultProjectDependencyAnalyzer Maven / Gradle / Ivy

The newest version!
/*
 * 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;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
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;

/**
 * 

DefaultProjectDependencyAnalyzer class.

* * @author Mark Hobson */ @Named @Singleton public class DefaultProjectDependencyAnalyzer implements ProjectDependencyAnalyzer { /** * ClassAnalyzer */ @Inject private ClassAnalyzer classAnalyzer; /** * DependencyAnalyzer */ @Inject private DependencyAnalyzer dependencyAnalyzer; /** {@inheritDoc} */ @Override public ProjectDependencyAnalysis analyze(MavenProject project, Collection excludedClasses) throws ProjectDependencyAnalyzerException { try { ClassesPatterns excludedClassesPatterns = new ClassesPatterns(excludedClasses); Map> artifactClassMap = buildArtifactClassMap(project, excludedClassesPatterns); Set mainDependencyClasses = buildMainDependencyClasses(project, excludedClassesPatterns); Set testDependencyClasses = buildTestDependencyClasses(project, excludedClassesPatterns); Set dependencyClasses = new HashSet<>(); dependencyClasses.addAll(mainDependencyClasses); dependencyClasses.addAll(testDependencyClasses); Set testOnlyDependencyClasses = buildTestOnlyDependencyClasses(mainDependencyClasses, testDependencyClasses); Map> usedArtifacts = buildUsedArtifacts(artifactClassMap, dependencyClasses); Set mainUsedArtifacts = buildUsedArtifacts(artifactClassMap, mainDependencyClasses).keySet(); Set testArtifacts = buildUsedArtifacts(artifactClassMap, testOnlyDependencyClasses) .keySet(); Set testOnlyArtifacts = removeAll(testArtifacts, mainUsedArtifacts); Set declaredArtifacts = buildDeclaredArtifacts(project); Set usedDeclaredArtifacts = new LinkedHashSet<>(declaredArtifacts); usedDeclaredArtifacts.retainAll(usedArtifacts.keySet()); Map> usedDeclaredArtifactsWithClasses = new LinkedHashMap<>(); for (Artifact a : usedDeclaredArtifacts) { usedDeclaredArtifactsWithClasses.put(a, usedArtifacts.get(a)); } Map> usedUndeclaredArtifactsWithClasses = new LinkedHashMap<>(usedArtifacts); Set usedUndeclaredArtifacts = removeAll(usedUndeclaredArtifactsWithClasses.keySet(), declaredArtifacts); usedUndeclaredArtifactsWithClasses.keySet().retainAll(usedUndeclaredArtifacts); Set unusedDeclaredArtifacts = new LinkedHashSet<>(declaredArtifacts); unusedDeclaredArtifacts = removeAll(unusedDeclaredArtifacts, usedArtifacts.keySet()); Set testArtifactsWithNonTestScope = getTestArtifactsWithNonTestScope(testOnlyArtifacts); return new ProjectDependencyAnalysis( usedDeclaredArtifactsWithClasses, usedUndeclaredArtifactsWithClasses, unusedDeclaredArtifacts, testArtifactsWithNonTestScope); } catch (IOException exception) { throw new ProjectDependencyAnalyzerException("Cannot analyze dependencies", exception); } } /** * This method defines a new way to remove the artifacts by using the conflict id. We don't care about the version * here because there can be only 1 for a given artifact anyway. * * @param start initial set * @param remove set to exclude * @return set with remove excluded */ private static Set removeAll(Set start, Set remove) { Set results = new LinkedHashSet<>(start.size()); for (Artifact artifact : start) { boolean found = false; for (Artifact artifact2 : remove) { if (artifact.getDependencyConflictId().equals(artifact2.getDependencyConflictId())) { found = true; break; } } if (!found) { results.add(artifact); } } return results; } private static Set getTestArtifactsWithNonTestScope(Set testOnlyArtifacts) { Set nonTestScopeArtifacts = new LinkedHashSet<>(); for (Artifact artifact : testOnlyArtifacts) { if (artifact.getScope().equals("compile")) { nonTestScopeArtifacts.add(artifact); } } return nonTestScopeArtifacts; } protected Map> buildArtifactClassMap(MavenProject project, ClassesPatterns excludedClasses) throws IOException { Map> artifactClassMap = new LinkedHashMap<>(); Set dependencyArtifacts = project.getArtifacts(); for (Artifact artifact : dependencyArtifacts) { File file = artifact.getFile(); if (file != null && file.getName().endsWith(".jar")) { // optimized solution for the jar case try (JarFile jarFile = new JarFile(file)) { Enumeration jarEntries = jarFile.entries(); Set classes = new HashSet<>(); while (jarEntries.hasMoreElements()) { String entry = jarEntries.nextElement().getName(); if (entry.endsWith(".class")) { String className = entry.replace('/', '.'); className = className.substring(0, className.length() - ".class".length()); if (!excludedClasses.isMatch(className)) { classes.add(className); } } } artifactClassMap.put(artifact, classes); } } else if (file != null && file.isDirectory()) { URL url = file.toURI().toURL(); Set classes = classAnalyzer.analyze(url, excludedClasses); artifactClassMap.put(artifact, classes); } } return artifactClassMap; } private static Set buildTestOnlyDependencyClasses( Set mainDependencyClasses, Set testDependencyClasses) { Set testOnlyDependencyClasses = new HashSet<>(testDependencyClasses); Set mainDepClassNames = mainDependencyClasses.stream() .map(DependencyUsage::getDependencyClass) .collect(Collectors.toSet()); testOnlyDependencyClasses.removeIf(u -> mainDepClassNames.contains(u.getDependencyClass())); return testOnlyDependencyClasses; } private Set buildMainDependencyClasses(MavenProject project, ClassesPatterns excludedClasses) throws IOException { String outputDirectory = project.getBuild().getOutputDirectory(); return buildDependencyClasses(outputDirectory, excludedClasses); } private Set buildTestDependencyClasses(MavenProject project, ClassesPatterns excludedClasses) throws IOException { String testOutputDirectory = project.getBuild().getTestOutputDirectory(); return buildDependencyClasses(testOutputDirectory, excludedClasses); } private Set buildDependencyClasses(String path, ClassesPatterns excludedClasses) throws IOException { URL url = new File(path).toURI().toURL(); return dependencyAnalyzer.analyzeUsages(url, excludedClasses); } private static Set buildDeclaredArtifacts(MavenProject project) { Set declaredArtifacts = project.getDependencyArtifacts(); if (declaredArtifacts == null) { declaredArtifacts = Collections.emptySet(); } return declaredArtifacts; } private static Map> buildUsedArtifacts( Map> artifactClassMap, Set dependencyClasses) { Map> usedArtifacts = new HashMap<>(); for (DependencyUsage classUsage : dependencyClasses) { Artifact artifact = findArtifactForClassName(artifactClassMap, classUsage.getDependencyClass()); if (artifact != null) { Set classesFromArtifact = usedArtifacts.get(artifact); if (classesFromArtifact == null) { classesFromArtifact = new HashSet<>(); usedArtifacts.put(artifact, classesFromArtifact); } classesFromArtifact.add(classUsage); } } return usedArtifacts; } private static Artifact findArtifactForClassName(Map> artifactClassMap, String className) { for (Map.Entry> entry : artifactClassMap.entrySet()) { if (entry.getValue().contains(className)) { return entry.getKey(); } } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy