Skip to content

Commit

Permalink
feat: avoid changing thread classloader
Browse files Browse the repository at this point in the history
  • Loading branch information
CarstenWickner committed Jan 3, 2024
1 parent 74cc79b commit e51670a
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 43 deletions.
49 changes: 19 additions & 30 deletions src/main/java/io/openapitools/swagger/GenerateMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,40 +110,29 @@ public void execute() throws MojoExecutionException, MojoFailureException {
return;
}

ClassLoader origClzLoader = Thread.currentThread().getContextClassLoader();
ClassLoader clzLoader = createClassLoader(origClzLoader);
Reader reader = new Reader(swaggerConfig == null ? new OpenAPI() : swaggerConfig.createSwaggerModel());

try {
// set the TCCL before everything else
Thread.currentThread().setContextClassLoader(clzLoader);

Reader reader = new Reader(swaggerConfig == null ? new OpenAPI() : swaggerConfig.createSwaggerModel());
JaxRSScanner reflectiveScanner = new JaxRSScanner(getLog(), createClassLoader(), resourcePackages, useResourcePackagesChildren);

JaxRSScanner reflectiveScanner = new JaxRSScanner(getLog(), resourcePackages, useResourcePackagesChildren);
Application application = resolveApplication(reflectiveScanner);
reader.setApplication(application);

Application application = resolveApplication(reflectiveScanner);
reader.setApplication(application);
OpenAPI swagger = OpenAPISorter.sort(reader.read(reflectiveScanner.classes()));

OpenAPI swagger = OpenAPISorter.sort(reader.read(reflectiveScanner.classes()));

if (outputDirectory.mkdirs()) {
getLog().debug("Created output directory " + outputDirectory);
}
if (outputDirectory.mkdirs()) {
getLog().debug("Created output directory " + outputDirectory);
}

outputFormats.forEach(format -> {
try {
File outputFile = new File(outputDirectory, outputFilename + "." + format.name().toLowerCase());
format.write(swagger, outputFile, prettyPrint);
if (attachSwaggerArtifact) {
projectHelper.attachArtifact(project, format.name().toLowerCase(), "swagger", outputFile);
}
} catch (IOException e) {
throw new RuntimeException("Unable write " + outputFilename + " document", e);
try {
for (OutputFormat format : outputFormats) {
File outputFile = new File(outputDirectory, outputFilename + "." + format.name().toLowerCase());
format.write(swagger, outputFile, prettyPrint);
if (attachSwaggerArtifact) {
projectHelper.attachArtifact(project, format.name().toLowerCase(), "swagger", outputFile);
}
});
} finally {
// reset the TCCL back to the original class loader
Thread.currentThread().setContextClassLoader(origClzLoader);
}
} catch (IOException e) {
throw new RuntimeException("Unable write " + outputFilename + " document", e);
}
}

Expand All @@ -164,15 +153,15 @@ private Application resolveApplication(JaxRSScanner reflectiveScanner) {
return ClassUtils.createInstance(appClazz);
}

private URLClassLoader createClassLoader(ClassLoader parent) {
private URLClassLoader createClassLoader() {
try {
Collection<String> dependencies = getDependentClasspathElements();
URL[] urls = new URL[dependencies.size()];
int index = 0;
for (String dependency : dependencies) {
urls[index++] = Paths.get(dependency).toUri().toURL();
}
return new URLClassLoader(urls, parent);
return new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
} catch (MalformedURLException e) {
throw new RuntimeException("Unable to create class loader with compiled classes", e);
} catch (DependencyResolutionRequiredException e) {
Expand Down
31 changes: 18 additions & 13 deletions src/main/java/io/openapitools/swagger/JaxRSScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -26,42 +25,48 @@ class JaxRSScanner {

private final Log log;

private final ClassGraph classGraph;

private final Set<String> resourcePackages;

private final boolean useResourcePackagesChildren;

public JaxRSScanner(Log log, Set<String> resourcePackages, Boolean useResourcePackagesChildren) {
public JaxRSScanner(Log log, ClassLoader clzLoader, Set<String> resourcePackages, Boolean useResourcePackagesChildren) {
this.log = log;
this.classGraph = new ClassGraph().enableClassInfo().enableAnnotationInfo()
.addClassLoader(clzLoader);
this.resourcePackages = resourcePackages == null ? Collections.emptySet() : new HashSet<>(resourcePackages);
this.useResourcePackagesChildren = Boolean.TRUE.equals(useResourcePackagesChildren);
}

Application applicationInstance() {
ClassGraph classGraph = new ClassGraph().enableClassInfo();
Application applicationInstance = null;
try (ScanResult scanResult = classGraph.scan()) {
List<ClassInfo> applicationClasses = scanResult.getSubclasses(Application.class.getName()).stream()
.filter(this::filterClassByResourcePackages)
.collect(Collectors.toList());
ClassInfoList applicationClasses = scanResult.getSubclasses(Application.class.getName())
.filter(this::filterClassByResourcePackages);
if (applicationClasses.size() == 1) {
return ClassUtils.createInstance(applicationClasses.get(0).loadClass(Application.class));
}
if (applicationClasses.size() > 1) {
applicationInstance = ClassUtils.createInstance(applicationClasses.get(0).loadClass(Application.class));
} else if (applicationClasses.size() > 1) {
log.warn("More than one javax.ws.rs.core.Application classes found on the classpath, skipping");
}
}
return null;
return applicationInstance;
}

Set<Class<?>> classes() {
ClassGraph classGraph = new ClassGraph().enableClassInfo().enableAnnotationInfo();
Set<Class<?>> classes;
try (ScanResult scanResult = classGraph.scan()) {
ClassInfoList apiClasses = scanResult.getClassesWithAnnotation(Path.class.getName());
ClassInfoList defClasses = scanResult.getClassesWithAnnotation(OpenAPIDefinition.class.getName());
return Stream.concat(apiClasses.stream(), defClasses.stream())
.filter(this::filterClassByResourcePackages)
classes = Stream.of(apiClasses, defClasses)
.flatMap(classList -> classList.filter(this::filterClassByResourcePackages).stream())
.map(ClassInfo::loadClass)
.collect(Collectors.toSet());
}
if (classes.isEmpty()) {
log.warn("No @Path or @OpenAPIDefinition annotated classes found in given resource packages: " + resourcePackages);
}
return classes;
}

private boolean filterClassByResourcePackages(ClassInfo cls) {
Expand Down

0 comments on commit e51670a

Please sign in to comment.