Skip to content

Commit

Permalink
maven plugin - Reduce amount of created jandex indexes.
Browse files Browse the repository at this point in the history
This introduces a blacklist of artifacts, for which no jandex index is ever created, since they won't have impact on the generated scheme.
Also, cache the indexes that are created using their gavct
  • Loading branch information
Postremus committed Nov 7, 2021
1 parent 604325c commit baf9bf2
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 78 deletions.
15 changes: 13 additions & 2 deletions tools/maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.2.1</version>
<artifactId>maven-core</artifactId>
</dependency>

<dependency>
Expand Down Expand Up @@ -65,6 +64,18 @@
<goalPrefix>smallrye-open-api</goalPrefix>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-component-metadata</artifactId>
<version>2.1.0</version>
<executions>
<execution>
<goals>
<goal>generate-metadata</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,26 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.eclipse.microprofile.openapi.OASConfig;
import org.eclipse.microprofile.openapi.models.OpenAPI;
import org.jboss.jandex.CompositeIndex;
import org.jboss.jandex.Index;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.Indexer;
import org.jboss.jandex.JarIndexer;
import org.jboss.jandex.Result;

import io.smallrye.openapi.api.OpenApiConfig;
import io.smallrye.openapi.api.OpenApiDocument;
Expand Down Expand Up @@ -81,18 +75,9 @@ public class GenerateSchemaMojo extends AbstractMojo {
@Parameter(defaultValue = "${project}", required = true)
private MavenProject mavenProject;

@Parameter(property = "project.compileClasspathElements", required = true, readonly = true)
private List<String> classpath;

@Parameter(defaultValue = "false", property = "skip")
private boolean skip;

/**
* Compiled classes of the project.
*/
@Parameter(defaultValue = "${project.build.outputDirectory}", property = "classesDir")
private File classesDir;

@Parameter(property = "configProperties")
private File configProperties;

Expand Down Expand Up @@ -176,73 +161,25 @@ public class GenerateSchemaMojo extends AbstractMojo {
@Parameter(property = "operationIdStrategy")
private String operationIdStrategy;

@Component
private MavenDependencyIndexCreator mavenDependencyIndexCreator;

@Override
public void execute() throws MojoExecutionException {
if (!skip) {
try {
IndexView index = createIndex();
IndexView index = mavenDependencyIndexCreator.createIndex(mavenProject, scanDependenciesDisable,
includeDependenciesScopes, includeDependenciesTypes);
OpenApiDocument schema = generateSchema(index);
write(schema);
} catch (IOException ex) {
} catch (Exception ex) {
getLog().error(ex);
throw new MojoExecutionException("Could not generate OpenAPI Schema", ex); // TODO allow failOnError = false ?
}
}
}

private IndexView createIndex() throws MojoExecutionException {
IndexView moduleIndex;
try {
moduleIndex = indexModuleClasses();
} catch (IOException e) {
throw new MojoExecutionException("Can't compute index", e);
}
if (!scanDependenciesDisable()) {
List<IndexView> indexes = new ArrayList<>();
indexes.add(moduleIndex);
for (Object a : mavenProject.getArtifacts()) {
Artifact artifact = (Artifact) a;
if (includeDependenciesScopes.contains(artifact.getScope())
&& includeDependenciesTypes.contains(artifact.getType())) {
try {
Result result = JarIndexer.createJarIndex(artifact.getFile(), new Indexer(),
false, false, false);
indexes.add(result.getIndex());
} catch (Exception e) {
getLog().error("Can't compute index of " + artifact.getFile().getAbsolutePath() + ", skipping", e);
}
}
}
return CompositeIndex.create(indexes);
} else {
return moduleIndex;
}
}

private boolean scanDependenciesDisable() {
if (scanDependenciesDisable == null) {
return false;
}
return scanDependenciesDisable;
}

// index the classes of this Maven module
private Index indexModuleClasses() throws IOException {
Indexer indexer = new Indexer();

try (Stream<Path> stream = Files.walk(classesDir.toPath())) {

List<Path> classFiles = stream
.filter(path -> path.toString().endsWith(".class"))
.collect(Collectors.toList());
for (Path path : classFiles) {
indexer.index(Files.newInputStream(path));
}
}
return indexer.complete();
}

private OpenApiDocument generateSchema(IndexView index) throws IOException {
private OpenApiDocument generateSchema(IndexView index) throws IOException, DependencyResolutionRequiredException {
OpenApiConfig openApiConfig = new MavenConfig(getProperties());

OpenAPI staticModel = generateStaticModel();
Expand Down Expand Up @@ -272,10 +209,9 @@ private OpenApiDocument generateSchema(IndexView index) throws IOException {
return document;
}

private ClassLoader getClassLoader() throws MalformedURLException {
private ClassLoader getClassLoader() throws MalformedURLException, DependencyResolutionRequiredException {
Set<URL> urls = new HashSet<>();

for (String element : classpath) {
for (String element : mavenProject.getCompileClasspathElements()) {
urls.add(new File(element).toURI().toURL());
}

Expand All @@ -302,7 +238,7 @@ private OpenAPI generateStaticModel() throws IOException {
}

private Path getStaticFile() {
Path classesPath = classesDir.toPath();
Path classesPath = new File(mavenProject.getBuild().getOutputDirectory()).toPath();

if (Files.exists(classesPath)) {
Path resourcePath = Paths.get(classesPath.toString(), META_INF_OPENAPI_YAML);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package io.smallrye.openapi.mavenplugin;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.jboss.jandex.CompositeIndex;
import org.jboss.jandex.Index;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.Indexer;
import org.jboss.jandex.JarIndexer;
import org.jboss.jandex.Result;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

@Component(role = MavenDependencyIndexCreator.class, instantiationStrategy = "singleton")
public class MavenDependencyIndexCreator {

private final Cache<String, IndexView> indexCache = CacheBuilder.newBuilder().build();

private final Set<String> ignoredArtifacts = new HashSet<>();

@Requirement
private Logger logger;

public MavenDependencyIndexCreator() {
ignoredArtifacts.add("org.graalvm.sdk:graal-sdk");
ignoredArtifacts.add("org.yaml:snakeyaml");
ignoredArtifacts.add("org.wildfly.common:wildfly-common");
ignoredArtifacts.add("com.fasterxml.jackson.core:jackson-core");
ignoredArtifacts.add("com.fasterxml.jackson.core:jackson-databind");
ignoredArtifacts.add("io.smallrye.reactive:smallrye-mutiny-vertx-core");
ignoredArtifacts.add("commons-io:commons-io");
ignoredArtifacts.add("io.smallrye.reactive:mutiny");
ignoredArtifacts.add("org.jboss.narayana.jta:narayana-jta");
ignoredArtifacts.add("org.glassfish.jaxb:jaxb-runtime");
ignoredArtifacts.add("com.github.ben-manes.caffeine:caffeine");
ignoredArtifacts.add("org.hibernate.validator:hibernate-validator");
ignoredArtifacts.add("io.smallrye.config:smallrye-config-core");
ignoredArtifacts.add("com.thoughtworks.xstream:xstream");
ignoredArtifacts.add("com.github.javaparser:javaparser-core");
ignoredArtifacts.add("org.jboss:jandex");

ignoredArtifacts.add("antlr");
ignoredArtifacts.add("io.netty");
ignoredArtifacts.add("org.drools");
ignoredArtifacts.add("net.bytebuddy");
ignoredArtifacts.add("org.hibernate");
ignoredArtifacts.add("org.kie");
ignoredArtifacts.add("org.postgresql");
ignoredArtifacts.add("org.apache.httpcomponents");
}

public IndexView createIndex(MavenProject mavenProject, Boolean scanDependenciesDisable,
List<String> includeDependenciesScopes, List<String> includeDependenciesTypes) throws Exception {

List<Map.Entry<Artifact, Duration>> indexDurations = new ArrayList<>();

IndexView moduleIndex = timeAndCache(indexDurations, mavenProject.getArtifact(), () -> {
try {
return indexModuleClasses(mavenProject);
} catch (IOException e) {
throw new MojoExecutionException("Can't compute index", e);
}
});

if (scanDependenciesDisable != null && !scanDependenciesDisable) {
return moduleIndex;
}

List<IndexView> indexes = new ArrayList<>();
indexes.add(moduleIndex);
for (Artifact artifact : mavenProject.getArtifacts()) {
if (isIgnored(artifact, includeDependenciesScopes, includeDependenciesTypes)) {
continue;
}

IndexView artifactIndex = timeAndCache(indexDurations, artifact, () -> {
try {
Result result = JarIndexer.createJarIndex(artifact.getFile(), new Indexer(),
false, false, false);
return result.getIndex();
} catch (Exception e) {
logger.error("Can't compute index of " + artifact.getFile().getAbsolutePath() + ", skipping", e);
return null;
}
});

if (artifactIndex != null) {
indexes.add(artifactIndex);
}
}

printIndexDurations(indexDurations);

return CompositeIndex.create(indexes);
}

private void printIndexDurations(List<Map.Entry<Artifact, Duration>> indexDurations) {
if (logger.isDebugEnabled()) {
indexDurations.sort(Map.Entry.comparingByValue());

indexDurations.forEach(e -> {
if (e.getValue().toMillis() > 25) {
logger.debug(buildGAVCTString(e.getKey()) + " " + e.getValue());
}
});
}
}

private boolean isIgnored(Artifact artifact, List<String> includeDependenciesScopes,
List<String> includeDependenciesTypes) {
return !includeDependenciesScopes.contains(artifact.getScope())
|| !includeDependenciesTypes.contains(artifact.getType())
|| ignoredArtifacts.contains(artifact.getGroupId())
|| ignoredArtifacts.contains(artifact.getGroupId() + ":" + artifact.getArtifactId());
}

private IndexView timeAndCache(List<Map.Entry<Artifact, Duration>> indexDurations, Artifact artifact,
Callable<IndexView> callable) throws Exception {
LocalDateTime start = LocalDateTime.now();
IndexView result = indexCache.get(buildGAVCTString(artifact), callable);
LocalDateTime end = LocalDateTime.now();

Duration duration = Duration.between(start, end);
indexDurations.add(new AbstractMap.SimpleEntry<>(artifact, duration));

return result;
}

// index the classes of this Maven module
private Index indexModuleClasses(MavenProject mavenProject) throws IOException {
Indexer indexer = new Indexer();

try (Stream<Path> stream = Files.walk(new File(mavenProject.getBuild().getOutputDirectory()).toPath())) {

List<Path> classFiles = stream
.filter(path -> path.toString().endsWith(".class"))
.collect(Collectors.toList());
for (Path path : classFiles) {
indexer.index(Files.newInputStream(path));
}
}
return indexer.complete();
}

private String buildGAVCTString(Artifact artifact) {
return artifact.getGroupId() +
":" +
artifact.getArtifactId() +
":" +
artifact.getVersion() +
":" +
artifact.getClassifier() +
":" +
artifact.getType();
}
}

0 comments on commit baf9bf2

Please sign in to comment.