Skip to content

Commit 3aa352a

Browse files
committed
Merge pull request #45202 from nosan
* gh-45202: Polish "Use ClassLoader with ArchitectureCheck" Use ClassLoader with ArchitectureCheck Closes gh-45202
2 parents 482f56d + 927e7db commit 3aa352a

File tree

7 files changed

+188
-141
lines changed

7 files changed

+188
-141
lines changed

Diff for: buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java

+38-8
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@
1818

1919
import java.io.File;
2020
import java.io.IOException;
21+
import java.net.URL;
22+
import java.net.URLClassLoader;
2123
import java.nio.file.Files;
2224
import java.nio.file.Path;
2325
import java.nio.file.StandardOpenOption;
26+
import java.util.ArrayList;
2427
import java.util.Collections;
2528
import java.util.List;
29+
import java.util.concurrent.Callable;
2630
import java.util.function.Supplier;
2731
import java.util.stream.Stream;
2832

@@ -33,11 +37,13 @@
3337
import org.gradle.api.DefaultTask;
3438
import org.gradle.api.Task;
3539
import org.gradle.api.Transformer;
40+
import org.gradle.api.file.ConfigurableFileCollection;
3641
import org.gradle.api.file.DirectoryProperty;
3742
import org.gradle.api.file.FileCollection;
3843
import org.gradle.api.file.FileTree;
3944
import org.gradle.api.provider.ListProperty;
4045
import org.gradle.api.provider.Property;
46+
import org.gradle.api.tasks.Classpath;
4147
import org.gradle.api.tasks.IgnoreEmptyDirectories;
4248
import org.gradle.api.tasks.Input;
4349
import org.gradle.api.tasks.InputFiles;
@@ -58,6 +64,7 @@
5864
* @author Scott Frederick
5965
* @author Ivan Malutin
6066
* @author Phillip Webb
67+
* @author Dmytro Nosan
6168
*/
6269
public abstract class ArchitectureCheck extends DefaultTask {
6370

@@ -80,14 +87,17 @@ private List<String> asDescriptions(List<ArchRule> rules) {
8087
}
8188

8289
@TaskAction
83-
void checkArchitecture() throws IOException {
84-
JavaClasses javaClasses = new ClassFileImporter().importPaths(classFilesPaths());
85-
List<EvaluationResult> violations = evaluate(javaClasses).filter(EvaluationResult::hasViolation).toList();
86-
File outputFile = getOutputDirectory().file("failure-report.txt").get().getAsFile();
87-
writeViolationReport(violations, outputFile);
88-
if (!violations.isEmpty()) {
89-
throw new VerificationException("Architecture check failed. See '" + outputFile + "' for details.");
90-
}
90+
void checkArchitecture() throws Exception {
91+
withCompileClasspath(() -> {
92+
JavaClasses javaClasses = new ClassFileImporter().importPaths(classFilesPaths());
93+
List<EvaluationResult> violations = evaluate(javaClasses).filter(EvaluationResult::hasViolation).toList();
94+
File outputFile = getOutputDirectory().file("failure-report.txt").get().getAsFile();
95+
writeViolationReport(violations, outputFile);
96+
if (!violations.isEmpty()) {
97+
throw new VerificationException("Architecture check failed. See '" + outputFile + "' for details.");
98+
}
99+
return null;
100+
});
91101
}
92102

93103
private List<Path> classFilesPaths() {
@@ -98,6 +108,22 @@ private Stream<EvaluationResult> evaluate(JavaClasses javaClasses) {
98108
return getRules().get().stream().map((rule) -> rule.evaluate(javaClasses));
99109
}
100110

111+
private void withCompileClasspath(Callable<?> callable) throws Exception {
112+
ClassLoader previous = Thread.currentThread().getContextClassLoader();
113+
try {
114+
List<URL> urls = new ArrayList<>();
115+
for (File file : getCompileClasspath().getFiles()) {
116+
urls.add(file.toURI().toURL());
117+
}
118+
ClassLoader classLoader = new URLClassLoader(urls.toArray(new URL[0]), getClass().getClassLoader());
119+
Thread.currentThread().setContextClassLoader(classLoader);
120+
callable.call();
121+
}
122+
finally {
123+
Thread.currentThread().setContextClassLoader(previous);
124+
}
125+
}
126+
101127
private void writeViolationReport(List<EvaluationResult> violations, File outputFile) throws IOException {
102128
outputFile.getParentFile().mkdirs();
103129
StringBuilder report = new StringBuilder();
@@ -126,6 +152,10 @@ final FileTree getInputClasses() {
126152
return this.classes.getAsFileTree();
127153
}
128154

155+
@InputFiles
156+
@Classpath
157+
public abstract ConfigurableFileCollection getCompileClasspath();
158+
129159
@Optional
130160
@InputFiles
131161
@PathSensitive(PathSensitivity.RELATIVE)

Diff for: buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitecturePlugin.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@ private void registerTasks(Project project) {
4949
TaskProvider<ArchitectureCheck> checkPackageTangles = project.getTasks()
5050
.register("checkArchitecture" + StringUtils.capitalize(sourceSet.getName()), ArchitectureCheck.class,
5151
(task) -> {
52+
task.getCompileClasspath().from(sourceSet.getCompileClasspath());
5253
task.setClasses(sourceSet.getOutput().getClassesDirs());
5354
task.getResourcesDirectory().set(sourceSet.getOutput().getResourcesDir());
5455
task.dependsOn(sourceSet.getProcessResourcesTaskName());

0 commit comments

Comments
 (0)