|
|
@@ -8,7 +8,8 @@ package net.ranides.assira.reflection.util;
|
|
|
|
|
|
import net.ranides.assira.collection.iterators.EnumerationUtils;
|
|
|
import net.ranides.assira.collection.iterators.ForwardSpliterator;
|
|
|
-import net.ranides.assira.collection.iterators.IteratorUtils;
|
|
|
+import net.ranides.assira.collection.query.CQuery;
|
|
|
+import net.ranides.assira.collection.query.CQueryBuilder;
|
|
|
import net.ranides.assira.generic.ValueUtils;
|
|
|
import net.ranides.assira.io.ZipReader;
|
|
|
import net.ranides.assira.io.uri.URIUtils;
|
|
|
@@ -38,14 +39,19 @@ public final class PackageScanner {
|
|
|
private ClassLoader loader;
|
|
|
|
|
|
private PackageScanner() {
|
|
|
- /* utility class */
|
|
|
+ // do nothing
|
|
|
}
|
|
|
|
|
|
public static PackageScanner scanner() {
|
|
|
return new PackageScanner();
|
|
|
}
|
|
|
|
|
|
- public PackageScanner root(String root) {
|
|
|
+ public PackageScanner scope(String root) {
|
|
|
+ this.root = StringUtils.replace(root, '.', '/');
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public PackageScanner directory(String root) {
|
|
|
this.root = root;
|
|
|
return this;
|
|
|
}
|
|
|
@@ -55,15 +61,19 @@ public final class PackageScanner {
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
- public Stream<Class<?>> types() throws IOException {
|
|
|
- return names().map(toclass(cloader())).filter(Objects::nonNull);
|
|
|
+ public CQuery<Class<?>> types() throws IOException {
|
|
|
+ return names().map(toClass(cloader())).filter(Objects::nonNull);
|
|
|
+ }
|
|
|
+
|
|
|
+ public CQuery<String> names() throws IOException {
|
|
|
+ return files().filter(PackageScanner::isClass).map(PackageScanner::toClassName);
|
|
|
}
|
|
|
|
|
|
- public Stream<String> names() throws IOException {
|
|
|
+ public CQuery<String> files() throws IOException {
|
|
|
if(root == null) {
|
|
|
- return StreamSupport.stream(new PackageSpliterator(), false);
|
|
|
+ return CQueryBuilder.fromSpliterator(() -> new PackageSpliterator());
|
|
|
} else {
|
|
|
- return StreamSupport.stream(new PackageSpliterator(root, cloader()), false);
|
|
|
+ return CQueryBuilder.fromSpliterator(() -> new PackageSpliterator(root, cloader()));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -72,11 +82,11 @@ public final class PackageScanner {
|
|
|
}
|
|
|
|
|
|
private static final class PackageSpliterator extends ForwardSpliterator<String> {
|
|
|
-
|
|
|
+
|
|
|
private final String nroot;
|
|
|
private final String croot;
|
|
|
private final Iterator<String> resources;
|
|
|
-
|
|
|
+
|
|
|
private Spliterator<String> current;
|
|
|
|
|
|
public PackageSpliterator() {
|
|
|
@@ -85,19 +95,19 @@ public final class PackageScanner {
|
|
|
this.resources = Collections.singleton(PackageScanner.class.getProtectionDomain().getCodeSource().getLocation().getPath()+"!").iterator();
|
|
|
this.current = Collections.<String>emptyList().spliterator();
|
|
|
}
|
|
|
-
|
|
|
- public PackageSpliterator(String root, ClassLoader loader) throws IOException {
|
|
|
- this.nroot = (root==null)? ":" : (root + ".");
|
|
|
- this.croot = StringUtils.replace(root, '.', '/');
|
|
|
+
|
|
|
+ public PackageSpliterator(String root, ClassLoader loader) throws IOException {
|
|
|
+ this.nroot = (root==null)? ":" : (root + "/");
|
|
|
+ this.croot = root;
|
|
|
this.resources = EnumerationUtils.map(loader.getResources(croot), URL::getPath);
|
|
|
this.current = Collections.<String>emptyList().spliterator();
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- @Override
|
|
|
- public boolean tryAdvance(Consumer<? super String> action) {
|
|
|
+ @Override
|
|
|
+ public boolean tryAdvance(Consumer<? super String> action) {
|
|
|
return current.tryAdvance(action) || tryAdvanceResource(action);
|
|
|
- }
|
|
|
-
|
|
|
+ }
|
|
|
+
|
|
|
private boolean tryAdvanceResource(Consumer<? super String> action) {
|
|
|
if(!resources.hasNext()) {
|
|
|
return false;
|
|
|
@@ -107,7 +117,7 @@ public final class PackageScanner {
|
|
|
current = file.isDirectory() ? forDirectory(file.toPath()) : forJAR(uri);
|
|
|
return current.tryAdvance(action);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
private Spliterator<String> forJAR(String uri) {
|
|
|
try {
|
|
|
String jar = StringUtils.between(uri, ":", "!");
|
|
|
@@ -119,19 +129,19 @@ public final class PackageScanner {
|
|
|
throw ExceptionUtils.rethrow(cause);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
private Spliterator<String> forDirectory(Path file) {
|
|
|
try {
|
|
|
return Files
|
|
|
- .walk(file)
|
|
|
- .filter(PackageScanner::isClass)
|
|
|
- .map(s -> nroot + toClassName(file.relativize(s)))
|
|
|
- .spliterator();
|
|
|
+ .walk(file)
|
|
|
+ .filter(p -> !Files.isDirectory(p))
|
|
|
+ .map(s -> StringUtils.replace(nroot + file.relativize(s), '\\','/'))
|
|
|
+ .spliterator();
|
|
|
} catch(IOException cause) {
|
|
|
throw ExceptionUtils.rethrow(cause);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
private final class JARSpliterator extends ForwardSpliterator<String> {
|
|
|
|
|
|
private final JarInputStream istream;
|
|
|
@@ -145,11 +155,8 @@ public final class PackageScanner {
|
|
|
try {
|
|
|
JarEntry entry;
|
|
|
while(null != (entry = istream.getNextJarEntry())) {
|
|
|
- String ename = entry.getName();
|
|
|
- if( ename.endsWith(".class") && ename.startsWith(croot) ) {
|
|
|
- action.accept(toClassName(ename));
|
|
|
- return true;
|
|
|
- }
|
|
|
+ action.accept(entry.getName());
|
|
|
+ return true;
|
|
|
}
|
|
|
istream.close();
|
|
|
return false;
|
|
|
@@ -160,13 +167,13 @@ public final class PackageScanner {
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- private static boolean isClass(Path path) {
|
|
|
- return path.getFileName().toString().endsWith(".class");
|
|
|
+ private static boolean isClass(String path) {
|
|
|
+ return path.endsWith(".class");
|
|
|
}
|
|
|
|
|
|
- private static Function<String, Class<?>> toclass(ClassLoader loader) {
|
|
|
+ private static Function<String, Class<?>> toClass(ClassLoader loader) {
|
|
|
return name -> {
|
|
|
try {
|
|
|
return Class.forName(name, false, loader);
|
|
|
@@ -175,11 +182,7 @@ public final class PackageScanner {
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
-
|
|
|
- private static String toClassName(Path path) {
|
|
|
- return toClassName(path.toString());
|
|
|
- }
|
|
|
-
|
|
|
+
|
|
|
private static String toClassName(String path) {
|
|
|
String fname = StringUtils.removeSuffix(path, ".class");
|
|
|
return StringUtils.replace(StringUtils.replace(fname, '/', '.'), '\\', '.');
|