diff --git a/Dorkbox-Util/src/dorkbox/util/annotation/AnnotationDetector.java b/Dorkbox-Util/src/dorkbox/util/annotation/AnnotationDetector.java index e5a61d2..8509331 100644 --- a/Dorkbox-Util/src/dorkbox/util/annotation/AnnotationDetector.java +++ b/Dorkbox-Util/src/dorkbox/util/annotation/AnnotationDetector.java @@ -180,14 +180,11 @@ public final class AnnotationDetector implements Builder, Cursor { // "(Ljava/lang/String;II)I" String, int, int as arguments, return type int private String methodDescriptor; - private AnnotationDetector(final File[] filesOrDirectories, final String[] pkgNameFilter) { - this(Thread.currentThread().getContextClassLoader(), filesOrDirectories, null, pkgNameFilter); - } - private AnnotationDetector(ClassLoader loader, final File[] filesOrDirectories, ClassIterator iterator, final String[] pkgNameFilter) { this.loader = loader; if (iterator == null) { this.cfIterator = new ClassFileIterator(filesOrDirectories, pkgNameFilter); + if (filesOrDirectories.length == 0) { LOG.warn("No files or directories to scan!"); } else if (LOG.isTraceEnabled()) { @@ -213,7 +210,6 @@ public final class AnnotationDetector implements Builder, Cursor { throws IOException { final ClassLoader loader = Thread.currentThread().getContextClassLoader(); - return scanClassPath(loader, packageNames); } @@ -225,27 +221,67 @@ public final class AnnotationDetector implements Builder, Cursor { public static Builder scanClassPath(ClassLoader loader, final String... packageNames) throws IOException { - final Set files = new HashSet(); final String[] pkgNameFilter; - if (packageNames.length == 0) { - pkgNameFilter = null; - final String[] fileNames = System.getProperty("java.class.path").split(File.pathSeparator); - for (int i = 0; i < fileNames.length; ++i) { - files.add(new File(fileNames[i])); - } - } else { - pkgNameFilter = new String[packageNames.length]; - for (int i = 0; i < pkgNameFilter.length; ++i) { - pkgNameFilter[i] = packageNames[i].replace('.', '/'); - if (!pkgNameFilter[i].endsWith("/")) { - pkgNameFilter[i] = pkgNameFilter[i].concat("/"); + + // DORKBOX added + boolean isCustomLoader = "dorkbox.classloader.ClassLoader" == loader.getClass().getName(); + if (isCustomLoader) { + final List fileNames; + + // scanning the classpath + if (packageNames.length == 0) { + pkgNameFilter = null; + List asList = Arrays.asList(System.getProperty("java.class.path").split(File.pathSeparator)); + fileNames = new ArrayList(asList.size()); + for (String s : asList) { + File file = new File(s); + fileNames.add(file.toURI().toURL()); } } - for (final String packageName : pkgNameFilter) { - addFiles(loader, packageName, files); + // scanning specific packages + else { + pkgNameFilter = new String[packageNames.length]; + for (int i = 0; i < pkgNameFilter.length; ++i) { + pkgNameFilter[i] = packageNames[i].replace('.', '/'); + if (!pkgNameFilter[i].endsWith("/")) { + pkgNameFilter[i] = pkgNameFilter[i].concat("/"); + } + } + + fileNames = new ArrayList(); + for (final String packageName : pkgNameFilter) { + final Enumeration resourceEnum = loader.getResources(packageName); + while (resourceEnum.hasMoreElements()) { + final URL url = resourceEnum.nextElement(); + fileNames.add(url); + } + } } + + return new AnnotationDetector(loader, null, new CustomClassloaderIterator(fileNames, packageNames), pkgNameFilter); + } else { + final Set files = new HashSet(); + + if (packageNames.length == 0) { + pkgNameFilter = null; + final String[] fileNames = System.getProperty("java.class.path").split(File.pathSeparator); + for (int i = 0; i < fileNames.length; ++i) { + files.add(new File(fileNames[i])); + } + } else { + pkgNameFilter = new String[packageNames.length]; + for (int i = 0; i < pkgNameFilter.length; ++i) { + pkgNameFilter[i] = packageNames[i].replace('.', '/'); + if (!pkgNameFilter[i].endsWith("/")) { + pkgNameFilter[i] = pkgNameFilter[i].concat("/"); + } + } + for (final String packageName : pkgNameFilter) { + addFiles(loader, packageName, files); + } + } + return new AnnotationDetector(loader, files.toArray(new File[files.size()]), null, pkgNameFilter); } - return new AnnotationDetector(loader, files.toArray(new File[files.size()]), null, pkgNameFilter); } /** @@ -269,7 +305,7 @@ public final class AnnotationDetector implements Builder, Cursor { * Scan all files in the specified jar files and directories. */ public static Builder scanFiles(final File... filesOrDirectories) { - return new AnnotationDetector(filesOrDirectories, null); + return new AnnotationDetector(Thread.currentThread().getContextClassLoader(), filesOrDirectories, null, null); } /** @@ -515,8 +551,9 @@ public final class AnnotationDetector implements Builder, Cursor { // Handle JBoss VFS URL's which look like (example package 'nl.dvelop'): // vfs:/foo/bar/website.war/WEB-INF/classes/nl/dvelop/ // vfs:/foo/bar/website.war/WEB-INF/lib/dwebcore-0.0.1.jar/nl/dvelop/ - final boolean isVfs = "vfs".equals(url.getProtocol()); - if ("file".equals(url.getProtocol()) || isVfs) { + String protocol = url.getProtocol(); + final boolean isVfs = "vfs".equals(protocol); + if ("file".equals(protocol) || isVfs) { final File dir = toFile(url); if (dir.isDirectory()) { files.add(dir); diff --git a/Dorkbox-Util/src/dorkbox/util/annotation/CustomClassloaderIterator.java b/Dorkbox-Util/src/dorkbox/util/annotation/CustomClassloaderIterator.java new file mode 100644 index 0000000..8ad3ff6 --- /dev/null +++ b/Dorkbox-Util/src/dorkbox/util/annotation/CustomClassloaderIterator.java @@ -0,0 +1,91 @@ +package dorkbox.util.annotation; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import dorkbox.util.FileUtil; + +public class CustomClassloaderIterator implements ClassIterator { + + private volatile Iterator loaderFilesIterator; + private ClassFileIterator classFileIterator; + + // have to support + // 1 - scanning the classpath + // 2 - scanning a specific package + public CustomClassloaderIterator(List fileNames, String[] packageNames) throws IOException { + // if ANY of our filenames DO NOT start with "box", we have to add it as a file, so our iterator picks it up (and if dir, it's childred) + + Set files = new HashSet(); + Iterator iterator = fileNames.iterator(); + while (iterator.hasNext()) { + URL url = iterator.next(); + if (!url.getProtocol().equals("box")) { + try { + File file = FileUtil.normalize(new File(url.toURI())); + files.add(file); + iterator.remove(); + } catch (URISyntaxException ex) { + throw new IOException(ex.getMessage()); + } + } + } + + if (files.isEmpty()) { + this.classFileIterator = null; + } else { + this.classFileIterator = new ClassFileIterator(files.toArray(new File[0]), packageNames); + } + + + this.loaderFilesIterator = fileNames.iterator(); + } + + @Override + public String getName() { + // not needed + return null; + } + + @Override + public boolean isFile() { + if (this.classFileIterator != null) { + return this.classFileIterator.isFile(); + } + + return false; + } + + @Override + public InputStream next(FilenameFilter filter) throws IOException { + if (this.classFileIterator != null) { + while (true) { + InputStream next = this.classFileIterator.next(filter); + if (next == null) { + this.classFileIterator = null; + } else { + String name = this.classFileIterator.getName(); + if (name.endsWith(".class")) { + return next; + } + } + } + } + + if (this.loaderFilesIterator.hasNext()) { + URL next = this.loaderFilesIterator.next(); + return next.openStream(); + } + + return null; + } + +}