Skip to content

Commit

Permalink
Processors should be considered as rightful dependencies (ASSERT-KTH#82)
Browse files Browse the repository at this point in the history
Co-authored-by: Alexandre Fillatre <[email protected]>
Co-authored-by: cesarsotovalero <[email protected]>
  • Loading branch information
3 people committed Mar 31, 2022
1 parent 1ccbba2 commit 9bcdadc
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,30 @@
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
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.Optional;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import lombok.extern.slf4j.Slf4j;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import se.kth.depclean.core.analysis.asm.ASMDependencyAnalyzer;
import se.kth.depclean.core.analysis.graph.DefaultCallGraph;

/**
* The principal class that perform the dependency analysis in a Maven project.
*/
@Slf4j
@Component(role = ProjectDependencyAnalyzer.class)
public class DefaultProjectDependencyAnalyzer implements ProjectDependencyAnalyzer {

Expand Down Expand Up @@ -97,10 +102,12 @@ public ProjectDependencyAnalysis analyze(MavenProject project) throws ProjectDep
/* ******************** usage analysis ********************* */

// search for the dependencies used by the project
Set<Artifact> usedArtifacts = collectUsedArtifacts(
collectUsedArtifacts(
artifactClassesMap,
DefaultCallGraph.referencedClassMembers(projectClasses)
);
Set<Artifact> usedArtifacts = collectUsedArtifactsFromProcessors(project, artifactClassesMap);


/* ******************** results as statically used at the bytecode *********************** */

Expand All @@ -122,6 +129,47 @@ public ProjectDependencyAnalysis analyze(MavenProject project) throws ProjectDep
}
}

/**
* Maven processors are defined like this.
* <pre>
* {@code
* <plugin>
* <groupId>org.bsc.maven</groupId>
* <artifactId>maven-processor-plugin</artifactId>
* <executions>
* <execution>
* <id>process</id>
* [...]
* <configuration>
* <processors>
* <processor>XXXProcessor</processor>
* </processors>
* </configuration>
* </execution>
* </executions>
* </plugin>
* }
* </pre>
*
* @param project the maven project
* @param artifactClassesMap previously built artifacts map
* @return all used artifacts so far
*/
private Set<Artifact> collectUsedArtifactsFromProcessors(MavenProject project,
Map<Artifact, Set<String>> artifactClassesMap) {
final Xpp3Dom[] processors = Optional.ofNullable(project.getPlugin("org.bsc.maven:maven-processor-plugin"))
.map(plugin -> plugin.getExecutionsAsMap().get("process"))
.map(exec -> (Xpp3Dom) exec.getConfiguration())
.map(config -> config.getChild("processors"))
.map(Xpp3Dom::getChildren)
.orElse(new Xpp3Dom[0]);
Arrays.stream(processors)
.forEach(processor -> findArtifactForClassName(artifactClassesMap, processor.getValue())
.ifPresent(artifact -> artifactUsedClassesMap.putIfAbsent(artifact, new HashSet<>()))
);
return artifactUsedClassesMap.keySet();
}

/**
* Returns a map with the artifacts (dependencies) in a Maven project and their corresponding classes.
*
Expand Down Expand Up @@ -176,28 +224,21 @@ private void buildDependenciesDependencyClasses(MavenProject project) throws IOE

private Set<Artifact> collectUsedArtifacts(Map<Artifact, Set<String>> artifactClassMap,
Set<String> referencedClasses) {
Set<Artifact> usedArtifacts = new HashSet<>();
// find for used members in each class in the dependency classes
for (String clazz : referencedClasses) {
Artifact artifact = findArtifactForClassName(artifactClassMap, clazz);
if (artifact != null) {
if (!artifactUsedClassesMap.containsKey(artifact)) {
artifactUsedClassesMap.put(artifact, new HashSet<>());
}
artifactUsedClassesMap.get(artifact).add(clazz);
usedArtifacts.add(artifact);
}
findArtifactForClassName(artifactClassMap, clazz)
.ifPresent(artifact -> artifactUsedClassesMap.putIfAbsent(artifact, new HashSet<>()));
}
return usedArtifacts;
return artifactUsedClassesMap.keySet();
}

private Artifact findArtifactForClassName(Map<Artifact, Set<String>> artifactClassMap, String className) {
private Optional<Artifact> findArtifactForClassName(Map<Artifact, Set<String>> artifactClassMap, String className) {
for (Map.Entry<Artifact, Set<String>> entry : artifactClassMap.entrySet()) {
if (entry.getValue().contains(className)) {
return entry.getKey();
return Optional.of(entry.getKey());
}
}
return null;
return Optional.empty();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package se.kth.depclean;

import static com.soebes.itf.extension.assertj.MavenITAssertions.assertThat;

import com.soebes.itf.jupiter.extension.MavenGoal;
import com.soebes.itf.jupiter.extension.MavenJupiterExtension;
import com.soebes.itf.jupiter.extension.MavenTest;
import com.soebes.itf.jupiter.maven.MavenExecutionResult;
import org.junit.jupiter.api.DisplayName;

import static com.soebes.itf.extension.assertj.MavenITAssertions.assertThat;

/**
* This class executes integration tests against the DepCleanMojo. The projects used for testing are in
* src/test/resources-its/se/kth/depclean/DepCleanMojoIT. The results of the DepClean executions for each project are in
Expand All @@ -19,11 +18,31 @@
public class DepCleanMojoIT {

@MavenTest
@MavenGoal("package")
@DisplayName("Test that DepClean runs in an empty Maven project")
void empty_project(MavenExecutionResult result) {
assertThat(result).isFailure(); // should pass
}

@MavenTest
@DisplayName("Test that DepClean runs in a Maven project with processors")
void processor_used(MavenExecutionResult result) {
assertThat(result).isSuccessful().out()
.plain().contains(
"-------------------------------------------------------",
" D E P C L E A N A N A L Y S I S R E S U L T S",
"-------------------------------------------------------",
"USED DIRECT DEPENDENCIES [1]: ",
" org.mapstruct:mapstruct-processor:1.4.2.Final:provided (1 MB)",
"USED INHERITED DEPENDENCIES [0]: ",
"USED TRANSITIVE DEPENDENCIES [1]: ",
" com.fasterxml.jackson.core:jackson-core:2.12.2:compile (356 KB)",
"POTENTIALLY UNUSED DIRECT DEPENDENCIES [1]: ",
" com.fasterxml.jackson.core:jackson-databind:2.12.2:compile (1 MB)",
"POTENTIALLY UNUSED INHERITED DEPENDENCIES [0]: ",
"POTENTIALLY UNUSED TRANSITIVE DEPENDENCIES [1]: ",
" com.fasterxml.jackson.core:jackson-annotations:2.12.2:compile (73 KB)"
);
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.foo.bar</groupId>
<artifactId>foobar</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>foobar</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>

<mapstruct.version>1.4.2.Final</mapstruct.version>
</properties>

<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.2</version>
<!--<scope>test</scope>-->
</dependency>
<!-- Include only this mapstruct dependency to fix issue #76 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.soebes.itf.jupiter.extension</groupId>
<artifactId>itf-failure-plugin</artifactId>
<version>0.9.0</version>
<executions>
<execution>
<id>first_very_simple</id>
<phase>initialize</phase>
<goals>
<goal>failure</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>5.0-jdk8-rc1</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<processors>
<!-- Be sure to consider processors as rightful dependencies -->
<processor>org.mapstruct.ap.MappingProcessor</processor>
</processors>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>se.kth.castor</groupId>
<artifactId>depclean-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<goals>
<goal>depclean</goal>
</goals>
<!--<configuration>-->
<!-- <failIfUnusedDirect>true</failIfUnusedDirect>-->
<!-- <ignoreScopes>test,provided,import,runtime</ignoreScopes>-->
<!--</configuration>-->
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.util.Separators;


public class Main {
// private static final ObjectMapper converter = new ObjectMapper();
Separators separators = new Separators();
int field = 42;
}

0 comments on commit 9bcdadc

Please sign in to comment.