Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maven plugin: index output directory instead of project artifact, logs #1538

Merged
merged 1 commit into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.Charset;
Expand Down Expand Up @@ -323,18 +325,32 @@ private OpenApiDocument generateSchema(IndexView index) throws IOException, Depe
return document;
}

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

if (getLog().isDebugEnabled()) {
getLog().debug("Adding directories/artifacts to annotation scanner class loader:");
}

for (String element : mavenProject.getCompileClasspathElements()) {
getLog().debug("Adding " + element + " to annotation scanner class loader");
urls.add(new File(element).toURI().toURL());
if (getLog().isDebugEnabled()) {
getLog().debug(" " + element);
}

elements.add(new File(element).toURI());
}

return URLClassLoader.newInstance(
urls.toArray(new URL[0]),
Thread.currentThread().getContextClassLoader());
URL[] locators = elements.stream()
.map(uri -> {
try {
return uri.toURL();
} catch (MalformedURLException mue) {
throw new UncheckedIOException(mue);
}
})
.toArray(URL[]::new);

return URLClassLoader.newInstance(locators, Thread.currentThread().getContextClassLoader());
}

private OpenAPI generateAnnotationModel(IndexView indexView, OpenApiConfig openApiConfig, ClassLoader classLoader) {
Expand Down Expand Up @@ -399,7 +415,7 @@ private Map<String, String> getProperties() throws IOException {
Properties p = new Properties();
try (InputStream is = Files.newInputStream(configProperties.toPath())) {
p.load(is);
cp.putAll((Map) p);
p.stringPropertyNames().forEach(k -> cp.put(k, p.getProperty(k)));
}
}

Expand Down Expand Up @@ -473,17 +489,7 @@ private void write(OpenApiDocument schema) throws MojoExecutionException {
Files.createDirectories(directory);
}

Charset charset = Charset.defaultCharset();

if (!StringUtils.isBlank(encoding)) {
try {
charset = Charset.forName(encoding.trim());
} catch (IllegalCharsetNameException e) {
throw new MojoExecutionException("encoding parameter does not define a legal charset name", e);
} catch (UnsupportedCharsetException e) {
throw new MojoExecutionException("encoding parameter does not define a supported charset", e);
}
}
Charset charset = getCharset(encoding);

if (Stream.of(OutputFileFilter.ALL, OutputFileFilter.YAML)
.anyMatch(f -> f.equals(OutputFileFilter.valueOf(this.outputFileTypeFilter)))) {
Expand All @@ -502,6 +508,24 @@ private void write(OpenApiDocument schema) throws MojoExecutionException {
}
}

static Charset getCharset(String encoding) throws MojoExecutionException {
if (StringUtils.isBlank(encoding)) {
return Charset.defaultCharset();
}

Charset charset;

try {
charset = Charset.forName(encoding.trim());
} catch (IllegalCharsetNameException e) {
throw new MojoExecutionException("encoding parameter does not define a legal charset name", e);
} catch (UnsupportedCharsetException e) {
throw new MojoExecutionException("encoding parameter does not define a supported charset", e);
}

return charset;
}

private void writeSchemaFile(Path directory, String type, byte[] contents) throws IOException {
Path file = Paths.get(directory.toString(), schemaFilename + "." + type);
if (!Files.exists(file)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
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.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.maven.artifact.Artifact;
Expand Down Expand Up @@ -71,56 +73,61 @@ public MavenDependencyIndexCreator() {
}

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

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

List<File> artifacts = new ArrayList<>();
String buildOutput = mavenProject.getBuild().getOutputDirectory();
if (buildOutput != null) {
logger.debug("Build output: " + buildOutput);
artifacts.add(new File(buildOutput));
} else {
logger.warn("Build output is null!");
}

List<Artifact> artifacts = new ArrayList<>();
artifacts.add(mavenProject.getArtifact());
if (!scanDependenciesDisable) {
artifacts.addAll(mavenProject.getArtifacts());
mavenProject.getArtifacts()
.stream()
.filter(artifact -> !isIgnored(artifact, includeDependenciesScopes, includeDependenciesTypes))
.map(Artifact::getFile)
.filter(Objects::nonNull)
.forEach(artifacts::add);
}

List<IndexView> indexes = new ArrayList<>();
for (Artifact artifact : artifacts) {
if (isIgnored(artifact, includeDependenciesScopes, includeDependenciesTypes)) {
continue;
}

for (File artifact : artifacts) {
try {
if (artifact.getFile().isDirectory()) {
// Don't' cache local worskpace artifacts. Incremental compilation in IDE's would otherwise use the cached index instead of new one.
if (artifact.isDirectory()) {
// Don't cache local workspace artifacts. Incremental compilation in IDEs would otherwise use the cached index instead of new one.
// Right now, support for incremental compilation inside eclipse is blocked by: https://github.com/eclipse-m2e/m2e-core/issues/364#issuecomment-939987848
// target/classes
LocalDateTime start = LocalDateTime.now();
indexes.add(indexModuleClasses(artifact));
} else if (artifact.getFile().getName().endsWith(".jar")) {
Duration duration = Duration.between(start, LocalDateTime.now());
indexDurations.add(new AbstractMap.SimpleEntry<>(artifact, duration));
} else if (artifact.getName().endsWith(".jar")) {
IndexView artifactIndex = timeAndCache(indexDurations, artifact, () -> {
Result result = JarIndexer.createJarIndex(artifact.getFile(), new Indexer(),
Result result = JarIndexer.createJarIndex(artifact, new Indexer(),
false, false, false);
return result.getIndex();
});
indexes.add(artifactIndex);
}
} catch (IOException | ExecutionException e) {
logger.error("Can't compute index of " + artifact.getFile().getAbsolutePath() + ", skipping", e);
} catch (Exception e) {
logger.error("Can't compute index of " + artifact.getAbsolutePath() + ", skipping", e);
}

}

printIndexDurations(indexDurations);

return CompositeIndex.create(indexes);
}

private void printIndexDurations(List<Map.Entry<Artifact, Duration>> indexDurations) {
private void printIndexDurations(List<Map.Entry<File, 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());
}
});
logger.debug("Indexed directories/artifacts for annotation scanning:");
indexDurations.forEach(e -> logger.debug(" " + e.getKey() + " (index time " + e.getValue() + ")"));
}
}

Expand All @@ -137,10 +144,10 @@ private boolean isIgnored(Artifact artifact, List<String> includeDependenciesSco
|| ignoredArtifacts.contains(artifact.getGroupId() + ":" + artifact.getArtifactId());
}

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

Duration duration = Duration.between(start, end);
Expand All @@ -150,33 +157,20 @@ private IndexView timeAndCache(List<Map.Entry<Artifact, Duration>> indexDuration
}

// index the classes of this Maven module
private Index indexModuleClasses(Artifact artifact) throws IOException {

Indexer indexer = new Indexer();

private Index indexModuleClasses(File artifact) throws IOException {
// Check first if the classes directory exists, before attempting to create an index for the classes
if (artifact.getFile().exists()) {
try (Stream<Path> stream = Files.walk(artifact.getFile().toPath())) {
List<Path> classFiles = stream
if (artifact.exists()) {
try (Stream<Path> stream = Files.walk(artifact.toPath())) {
File[] classFiles = stream
.filter(path -> path.toString().endsWith(".class"))
.collect(Collectors.toList());
for (Path path : classFiles) {
indexer.index(Files.newInputStream(path));
}
.map(Path::toFile)
.toArray(File[]::new);
return Index.of(classFiles);
}
} else {
logger.warn("Module directory does not exist: " + artifact);
return Index.of(Collections.emptyList());
}
return indexer.complete();
}

private String buildGAVCTString(Artifact artifact) {
return artifact.getGroupId() +
":" +
artifact.getArtifactId() +
":" +
artifact.getVersion() +
":" +
artifact.getClassifier() +
":" +
artifact.getType();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.soebes.itf.jupiter.maven.MavenExecutionResult;

@MavenJupiterExtension
@MavenGoal("compile")
@MavenGoal("${project.groupId}:${project.artifactId}:${project.version}:generate-schema")
public class BasicIT extends SchemaTestBase {
@MavenTest
Expand All @@ -50,6 +51,8 @@ void basic_info(MavenExecutionResult result) throws IOException {

assertTrue(servers.contains(properties.get("server1").toString()));
assertTrue(servers.contains(properties.get("server2").toString()));

assertTrue(schema.getPaths().hasPathItem("/hello"));
};

testSchema(result, schemaConsumer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import com.soebes.itf.jupiter.maven.MavenExecutionResult;

import io.smallrye.openapi.runtime.io.OpenApiParser;

public class SchemaTestBase {

/**
Expand All @@ -25,13 +27,13 @@ private OpenAPI readJson(MavenExecutionResult result) throws IOException {
File openapiFile = new File(result.getMavenProjectResult().getTargetProjectDirectory(),
"target/generated/openapi.json");

return TestObjectMapperHolder.json().readValue(openapiFile, OpenAPI.class);
return OpenApiParser.parse(openapiFile.toURI().toURL());
}

private OpenAPI readYaml(MavenExecutionResult result) throws IOException {
File openapiFile = new File(result.getMavenProjectResult().getTargetProjectDirectory(),
"target/generated/openapi.yaml");

return TestObjectMapperHolder.yaml().readValue(openapiFile, OpenAPI.class);
return OpenApiParser.parse(openapiFile.toURI().toURL());
}
}

This file was deleted.

Loading