Skip to content

Commit 1c23add

Browse files
committed
fix: ClassPathScanner — Filter to NeonBee module JARs only
1 parent 2f3ea2a commit 1c23add

3 files changed

Lines changed: 51 additions & 11 deletions

File tree

src/main/java/io/neonbee/internal/scanner/ClassPathScanner.java

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.Map;
2828
import java.util.Set;
2929
import java.util.function.Predicate;
30+
import java.util.jar.Attributes;
3031
import java.util.jar.Manifest;
3132
import java.util.regex.Pattern;
3233
import java.util.stream.Stream;
@@ -70,6 +71,8 @@ public class ClassPathScanner {
7071
*/
7172
public static final Pattern SEPARATOR_PATTERN = Pattern.compile(";");
7273

74+
private static final String NEONBEE_MANIFEST_PREFIX = "NeonBee-";
75+
7376
private final ClassLoader classLoader;
7477

7578
/**
@@ -195,14 +198,15 @@ public Future<List<String>> scanForAnnotation(Vertx vertx,
195198
ElementType... elementTypes) {
196199

197200
Future<List<String>> classesFromDirectories = scanWithPredicate(vertx, ClassPathScanner::isClassFile);
198-
Future<List<String>> classesFromJars = scanJarFilesWithPredicate(vertx, ClassPathScanner::isClassFile)
199-
.map(uris -> {
200-
List<String> result = new ArrayList<>(uris.size());
201-
for (URI uri : uris) {
202-
result.add(JarHelper.extractFilePath(uri));
203-
}
204-
return result;
205-
});
201+
Future<List<String>> classesFromJars =
202+
scanJarFilesWithPredicate(vertx, ClassPathScanner::isClassFile, ClassPathScanner::isNeonBeeJar)
203+
.map(uris -> {
204+
List<String> result = new ArrayList<>(uris.size());
205+
for (URI uri : uris) {
206+
result.add(JarHelper.extractFilePath(uri));
207+
}
208+
return result;
209+
});
206210

207211
return Future.all(classesFromDirectories, classesFromJars).compose(v -> vertx.executeBlocking(() -> {
208212
List<AnnotationClassVisitor> classVisitors = new ArrayList<>(annotationClasses.size());
@@ -282,12 +286,16 @@ public Future<List<String>> scanWithPredicate(Vertx vertx, Predicate<String> pre
282286
* @return a future to a list of URIs representing the files which matches the given predicate
283287
*/
284288
public Future<List<URI>> scanJarFilesWithPredicate(Vertx vertx, Predicate<String> predicate) {
289+
return scanJarFilesWithPredicate(vertx, predicate, url -> true);
290+
}
291+
292+
private Future<List<URI>> scanJarFilesWithPredicate(Vertx vertx, Predicate<String> predicate,
293+
Predicate<URL> jarFilter) {
285294
return vertx.executeBlocking(() -> {
286295
List<URI> resources = new ArrayList<>();
287296
for (URL manifestResource : getManifestResourceURLs()) {
288297
URI uri = manifestResource.toURI();
289-
// filter for manifest files inside of jar files
290-
if ("jar".equals(uri.getScheme())) {
298+
if ("jar".equals(uri.getScheme()) && jarFilter.test(manifestResource)) {
291299
try (FileSystem fileSystem = FileSystems.newFileSystem(uri, Map.of())) {
292300
Path rootPath = fileSystem.getPath("/");
293301
scanDirectoryWithPredicateRecursive(rootPath, predicate)
@@ -299,6 +307,21 @@ public Future<List<URI>> scanJarFilesWithPredicate(Vertx vertx, Predicate<String
299307
});
300308
}
301309

310+
@SuppressWarnings("PMD.EmptyCatchBlock")
311+
private static boolean isNeonBeeJar(URL manifestUrl) {
312+
try (InputStream is = manifestUrl.openStream()) {
313+
Manifest manifest = new Manifest(is);
314+
Attributes attributes = manifest.getMainAttributes();
315+
for (Object key : attributes.keySet()) {
316+
if (key.toString().startsWith(NEONBEE_MANIFEST_PREFIX)) {
317+
return true;
318+
}
319+
}
320+
} catch (IOException e) { // NOPMD
321+
}
322+
return false;
323+
}
324+
302325
/**
303326
* Blocking method to get all resource URLs from the MANIFEST.MF file(s) on the class loader
304327
*

src/test/java/io/neonbee/internal/scanner/AnnotatedClassTemplate.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ public String getSimpleName() {
111111
}
112112

113113
public BasicJar asJar() throws IOException {
114-
return new BasicJar(Map.of(BasicJar.getJarEntryName(getClassName()), compileToByteCode()));
114+
return new BasicJar(Map.of("NeonBee-Module", "test"),
115+
Map.of(BasicJar.getJarEntryName(getClassName()), compileToByteCode()));
115116
}
116117
}

src/test/java/io/neonbee/internal/scanner/ClassPathScannerTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,22 @@ void scanWithPredicateJarFile(Vertx vertx, VertxTestContext testContext) throws
118118
})));
119119
}
120120

121+
@Test
122+
@DisplayName("Should skip non-NeonBee JARs during annotation scanning")
123+
void scanForAnnotationSkipsNonNeonBeeJars(Vertx vertx, VertxTestContext testContext) throws IOException {
124+
BasicJar nonNeonBeeJar = new BasicJar(
125+
Map.of(BasicJar.getJarEntryName("some.ThirdPartyClass"),
126+
new AnnotatedClassTemplate("ThirdPartyClass", "some")
127+
.setTypeAnnotation("@Deprecated").compileToByteCode()));
128+
129+
URLClassLoader urlc = new URLClassLoader(nonNeonBeeJar.writeToTempURL(), null);
130+
new ClassPathScanner(urlc).scanForAnnotation(vertx, Deprecated.class)
131+
.onComplete(testContext.succeeding(list -> testContext.verify(() -> {
132+
assertThat(list).isEmpty();
133+
testContext.completeNow();
134+
})));
135+
}
136+
121137
@Test
122138
@DisplayName("Should find classes which the class or any field or method within is annotated with a given annotation")
123139
void scanForAnnotation(Vertx vertx, VertxTestContext testContext) throws IOException {

0 commit comments

Comments
 (0)