浏览代码

new: EnumerationUtils#of
new: PackageScanner: new API, can scan whole runnable application-jar (launch4j exe supported)

Mariusz Sieroń 6 年之前
父节点
当前提交
f9bc20db41

+ 8 - 0
assira/src/main/java/net/ranides/assira/collection/iterators/EnumerationUtils.java

@@ -26,6 +26,14 @@ public final class EnumerationUtils {
         /* utility class */
     }
 
+    public static <T> Enumeration<T> of(T... values) {
+        return enumeration(Arrays.asList(values));
+    }
+
+    public static <T> Enumeration<T> enumeration(Iterable<? extends T> values) {
+        return enumeration(values.iterator());
+    }
+
     public static <T> Enumeration<T> enumeration(Iterator<? extends T> values) {
         return new Enumeration<T>() {
             @Override

+ 63 - 52
assira/src/main/java/net/ranides/assira/reflection/util/PackageScanner.java

@@ -6,6 +6,15 @@
  */
 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.generic.ValueUtils;
+import net.ranides.assira.io.ZipReader;
+import net.ranides.assira.io.uri.URIUtils;
+import net.ranides.assira.text.StringUtils;
+import net.ranides.assira.trace.ExceptionUtils;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -13,74 +22,74 @@ import java.net.URL;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.Set;
-import java.util.Spliterator;
+import java.util.*;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.jar.JarEntry;
 import java.util.jar.JarInputStream;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
-import net.ranides.assira.collection.iterators.ForwardSpliterator;
-import net.ranides.assira.io.ZipReader;
-import net.ranides.assira.text.StringUtils;
-import net.ranides.assira.io.uri.URIUtils;
-import net.ranides.assira.trace.ExceptionUtils;
 
 
 public final class PackageScanner {
 
+    private String root;
+
+    private ClassLoader loader;
+
     private PackageScanner() {
         /* utility class */
     }
-    
-    public static Set<Class<?>> getTypes(String root) throws IOException {
-        return getTypes(root, ClassUtils.loader());
-    }
-    
-    public static Set<Class<?>> getTypes(String root, ClassLoader loader) throws IOException {
-        return getTypeStream(root, loader).collect(Collectors.toSet());
-    }
-    
-    public static Stream<Class<?>> getTypeStream(String root) throws IOException {
-        return getTypeStream(root, ClassUtils.loader());
+
+    public static PackageScanner scanner() {
+        return new PackageScanner();
     }
-    
-    public static Stream<Class<?>> getTypeStream(String root, ClassLoader loader) throws IOException {
-        return getNameStream(root, loader).map(toclass(loader));
+
+    public PackageScanner root(String root) {
+        this.root = root;
+        return this;
     }
-    
-    public static Set<String> getNames(String root) throws IOException {
-        return getNames(root, ClassUtils.loader());
+
+    public PackageScanner loader(ClassLoader loader) {
+        this.loader = loader;
+        return this;
     }
-    
-    public static Set<String> getNames(String root, ClassLoader loader) throws IOException {
-        return getNameStream(root, loader).collect(Collectors.toSet());
+
+    public Stream<Class<?>> types() throws IOException {
+        return names().map(toclass(cloader())).filter(Objects::nonNull);
     }
-    
-    public static Stream<String> getNameStream(String root) throws IOException {
-        return getNameStream(root, ClassUtils.loader());
+
+    public Stream<String> names() throws IOException {
+        if(root == null) {
+            return StreamSupport.stream(new PackageSpliterator(), false);
+        } else {
+            return StreamSupport.stream(new PackageSpliterator(root, cloader()), false);
+        }
     }
-    
-    public static Stream<String> getNameStream(String root, ClassLoader loader) throws IOException {
-        return StreamSupport.stream(new PackageSpliterator(root, loader), false);
+
+    private ClassLoader cloader() {
+        return ValueUtils.or(loader, ClassUtils.loader());
     }
-    
+
     private static final class PackageSpliterator extends ForwardSpliterator<String> {
 		
         private final String nroot;
         private final String croot;
-        private final Enumeration<URL> resources;
+        private final Iterator<String> resources;
         
         private Spliterator<String> current;
+
+        public PackageSpliterator() {
+            this.nroot = "";
+            this.croot = "";
+            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 + ".";
+			this.nroot = (root==null)? ":" : (root + ".");
 			this.croot = StringUtils.replace(root, '.', '/');
-            this.resources =  loader.getResources(croot);
+            this.resources = EnumerationUtils.map(loader.getResources(croot), URL::getPath);
             this.current = Collections.<String>emptyList().spliterator();
 		}
 
@@ -90,11 +99,10 @@ public final class PackageScanner {
 		}
         
         private boolean tryAdvanceResource(Consumer<? super String> action) {
-            if(!resources.hasMoreElements()) {
+            if(!resources.hasNext()) {
                 return false;
             }
-            String str = resources.nextElement().getPath();
-            String uri = URIUtils.decodeURL(str, Charset.defaultCharset());
+            String uri = URIUtils.decodeURL(resources.next(), Charset.defaultCharset());
             File file = new File(uri);
             current = file.isDirectory() ? forDirectory(file.toPath()) : forJAR(uri);
             return current.tryAdvance(action);
@@ -103,6 +111,9 @@ public final class PackageScanner {
         private Spliterator<String> forJAR(String uri) {
             try {
                 String jar = StringUtils.between(uri, ":", "!");
+                if(jar.isEmpty()) {
+                    jar = uri;
+                }
                 return new JARSpliterator(ZipReader.openJAR(new FileInputStream(jar)));
             } catch (IOException cause) {
                 throw ExceptionUtils.rethrow(cause);
@@ -113,8 +124,8 @@ public final class PackageScanner {
             try {
                 return Files
                     .walk(file)
-                    .filter(PackageScanner::isclass)
-                    .map(s -> nroot + tocname(file.relativize(s)))
+                    .filter(PackageScanner::isClass)
+                    .map(s -> nroot + toClassName(file.relativize(s)))
                     .spliterator();
             } catch(IOException cause) {
                 throw ExceptionUtils.rethrow(cause);
@@ -136,7 +147,7 @@ public final class PackageScanner {
                     while(null != (entry = istream.getNextJarEntry())) {
                         String ename = entry.getName();
                         if( ename.endsWith(".class") && ename.startsWith(croot) ) {
-                            action.accept(tocname(ename));
+                            action.accept(toClassName(ename));
                             return true;
                         }
                     }
@@ -151,7 +162,7 @@ public final class PackageScanner {
 
 	}
 
-    private static boolean isclass(Path path) {
+    private static boolean isClass(Path path) {
         return path.getFileName().toString().endsWith(".class");
     }
     
@@ -159,17 +170,17 @@ public final class PackageScanner {
         return name -> {
             try {
                 return Class.forName(name, false, loader);
-            } catch(ClassNotFoundException cause) {
-                throw ExceptionUtils.rethrow(cause);
+            } catch(ClassNotFoundException | NoClassDefFoundError cause) {
+                return null;
             }
         };
     }
     
-    private static String tocname(Path path) {
-        return tocname(path.toString());
+    private static String toClassName(Path path) {
+        return toClassName(path.toString());
     }
     
-    private static String tocname(String path) {
+    private static String toClassName(String path) {
         String fname = StringUtils.removeSuffix(path, ".class");
         return StringUtils.replace(StringUtils.replace(fname, '/', '.'), '\\', '.');
     }

+ 1 - 1
assira/src/test/java/net/ranides/assira/ContractTesters.java

@@ -37,7 +37,7 @@ public final class ContractTesters {
             try {
                 RUNNER = new TestContractRunner(System.err);
                 
-                PackageScanner.getNameStream("net.ranides.assira")
+                PackageScanner.scanner().root("net.ranides.assira").names()
                     .map(newtester())
                     .filter(o -> o!=null)
                     .forEach(RUNNER::append);

+ 9 - 37
assira/src/test/java/net/ranides/assira/reflection/util/PackageScannerTest.java

@@ -25,25 +25,11 @@ public class PackageScannerTest {
         String ec2 = "net.ranides.assira.reflection.util.PackageScanner";
         String ec3 = "net.ranides.assira.reflection.util.PackageScannerTest";
         
-        assertTrue(PackageScanner.getNameStream(ns1).anyMatch(ec1::equals));
-        assertTrue(PackageScanner.getNameStream(ns2).anyMatch(ec2::equals));
-        assertTrue(PackageScanner.getNameStream(ns2).anyMatch(ec3::equals));
+        assertTrue(PackageScanner.scanner().root(ns1).names().anyMatch(ec1::equals));
+        assertTrue(PackageScanner.scanner().root(ns2).names().anyMatch(ec2::equals));
+        assertTrue(PackageScanner.scanner().root(ns2).names().anyMatch(ec3::equals));
     }
-    
-    @Test
-    public void testNames() throws IOException {
-        String ns1 = "net.ranides.assira.junit";
-        String ec1 = "net.ranides.assira.junit.LogObserver";
-        
-        String ns2 = "net.ranides.assira.reflection.util";
-        String ec2 = "net.ranides.assira.reflection.util.PackageScanner";
-        String ec3 = "net.ranides.assira.reflection.util.PackageScannerTest";
-        
-        assertTrue(PackageScanner.getNames(ns1).contains(ec1));
-        assertTrue(PackageScanner.getNames(ns2).contains(ec2));
-        assertTrue(PackageScanner.getNames(ns2).contains(ec3));
-    }
-    
+
     @Test
     public void testTypeStream() throws IOException {
         String ns1  = "net.ranides.assira.junit";
@@ -52,24 +38,10 @@ public class PackageScannerTest {
         String ns2  = "net.ranides.assira.reflection.util";
         Class<?> ec2 = net.ranides.assira.reflection.util.PackageScanner.class;
         Class<?> ec3 = net.ranides.assira.reflection.util.PackageScannerTest.class;
-        
-        assertTrue(PackageScanner.getTypeStream(ns1).anyMatch(ec1::equals));
-        assertTrue(PackageScanner.getTypeStream(ns2).anyMatch(ec2::equals));
-        assertTrue(PackageScanner.getTypeStream(ns2).anyMatch(ec3::equals));
-    }
-    
-    @Test
-    public void testTypes() throws IOException {
-        String ns1  = "net.ranides.assira.junit";
-        Class<?> ec1 = net.ranides.assira.junit.LogObserver.class;
-        
-        String ns2  = "net.ranides.assira.reflection.util";
-        Class<?> ec2 = net.ranides.assira.reflection.util.PackageScanner.class;
-        Class<?> ec3 = net.ranides.assira.reflection.util.PackageScannerTest.class;
-        
-        assertTrue(PackageScanner.getTypes(ns1).contains(ec1));
-        assertTrue(PackageScanner.getTypes(ns2).contains(ec2));
-        assertTrue(PackageScanner.getTypes(ns2).contains(ec3));
+
+        assertTrue(PackageScanner.scanner().root(ns1).types().anyMatch(ec1::equals));
+        assertTrue(PackageScanner.scanner().root(ns2).types().anyMatch(ec2::equals));
+        assertTrue(PackageScanner.scanner().root(ns2).types().anyMatch(ec3::equals));
     }
-    
+
 }