mxd 4 vuotta sitten
vanhempi
sitoutus
3912dcc167
1 muutettua tiedostoa jossa 102 lisäystä ja 17 poistoa
  1. 102 17
      src/main/java/org/ssssssss/magicapi/utils/ClassScanner.java

+ 102 - 17
src/main/java/org/ssssssss/magicapi/utils/ClassScanner.java

@@ -1,46 +1,48 @@
 package org.ssssssss.magicapi.utils;
 
-import sun.misc.Launcher;
 
+import org.ssssssss.script.functions.ObjectConvertExtension;
+
+import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Method;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
+import java.util.stream.Stream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
+
 public class ClassScanner {
 
 	public static List<String> scan() throws URISyntaxException {
 		ClassLoader loader = Thread.currentThread().getContextClassLoader();
 		Set<String> classes = new HashSet<>();
-		do{
-			if(loader instanceof URLClassLoader){
+		do {
+			if (loader instanceof URLClassLoader) {
 				classes.addAll(scan(((URLClassLoader) loader).getURLs()));
 			}
-		}while ((loader = loader.getParent()) != null);
-		classes.addAll(scan(Launcher.getBootstrapClassPath().getURLs()));
+		} while ((loader = loader.getParent()) != null);
+		classes.addAll(addJavaLibrary());
 		return new ArrayList<>(classes);
 	}
 
 	private static Set<String> scan(URL[] urls) throws URISyntaxException {
 		Set<String> classes = new HashSet<>();
-		if(urls != null){
+		if (urls != null) {
 			for (URL url : urls) {
 				String protocol = url.getProtocol();
-				if("file".equalsIgnoreCase(protocol)){
+				if ("file".equalsIgnoreCase(protocol)) {
 					String path = url.getPath();
 					if (path.toLowerCase().endsWith(".jar")) {
 						classes.addAll(scanJarFile(url));
 					} else {
 						classes.addAll(scanDirectory(new File(url.toURI()), null));
 					}
-				}else if("jar".equalsIgnoreCase(protocol)){
+				} else if ("jar".equalsIgnoreCase(protocol)) {
 					classes.addAll(scanJarFile(url));
 				}
 			}
@@ -48,6 +50,81 @@ public class ClassScanner {
 		return classes;
 	}
 
+	private static Set<String> addJavaLibrary() {
+		int version = checkJavaVersion();
+		if (version >= 9) {
+			return addJava9PlusLibrary();
+		}
+		return addJava8Library();
+	}
+
+	private static int checkJavaVersion() {
+		String version = System.getProperty("java.version");
+		int index = version.indexOf(".");
+		if (index > -1) {
+			String first = version.substring(0, index);
+			if (!"1".equals(first)) {
+				return ObjectConvertExtension.asInt(first, -1);
+			} else {
+				int endIndex = version.indexOf(".", index + 1);
+				return ObjectConvertExtension.asInt(version.substring(index + 1, endIndex), -1);
+			}
+		}
+		return -1;
+	}
+
+	/**
+	 * jdk 8
+	 */
+	private static Set<String> addJava8Library() {
+		try {
+			// 直接反射调用..
+			Object URLClassPath = Class.forName("sun.misc.Launcher").getMethod("getBootstrapClassPath").invoke(null);
+			return scan((URL[]) URLClassPath.getClass().getMethod("getURLs").invoke(URLClassPath));
+		} catch (Exception ignored) {
+		}
+		return Collections.emptySet();
+	}
+
+	/**
+	 * jdk 9+
+	 */
+	private static Set<String> addJava9PlusLibrary() {
+		Set<String> classes = new HashSet<>();
+		try {
+			//		ModuleLayer.boot().configuration().modules().stream().map(ResolvedModule::reference).forEach(ref -> {
+			//			try (ModuleReader reader = ref.open()) {
+			//				reader.list().forEach(System.out::println);
+			//			} catch (IOException e) {
+			//				e.printStackTrace();
+			//			}
+			//		});
+			Class<?> ModuleLayer = Class.forName("java.lang.ModuleLayer");
+			Object boot = ModuleLayer.getMethod("boot").invoke(null);
+			Object configuration = ModuleLayer.getMethod("configuration").invoke(boot);
+			Class<?> Configuration = Class.forName("java.lang.module.Configuration");
+			//Set<ResolvedModule>
+			Set<?> modules = (Set<?>) Configuration.getMethod("modules").invoke(configuration);
+			Method reference = Class.forName("java.lang.module.ResolvedModule").getMethod("reference");
+			Class<?> ModuleReader = Class.forName("java.lang.module.ModuleReader");
+			Method open = Class.forName("java.lang.module.ModuleReference").getMethod("open");
+			Method list = ModuleReader.getMethod("list");
+			modules.forEach(module -> {
+			});
+			for (Object module : modules) {
+				Object ref = reference.invoke(module);
+				try (Closeable reader = (Closeable) open.invoke(ref)) {
+					@SuppressWarnings("unchecked")
+					Stream<String> stream = (Stream<String>) list.invoke(reader);
+					stream.filter(ClassScanner::isClass).forEach(className -> classes.add(className.substring(0, className.length() - 6).replace("/", ".")));
+				} catch (IOException ignored) {
+				}
+			}
+		} catch (Exception ignored) {
+		}
+		return classes;
+	}
+
 	private static List<String> scanDirectory(File dir, String packageName) {
 		File[] files = dir.listFiles();
 		List<String> classes = new ArrayList<>();
@@ -64,8 +141,8 @@ public class ClassScanner {
 		return classes;
 	}
 
-	private static String filterFullName(String fullName){
-		if(fullName.startsWith("BOOT-INF.classes.")){
+	private static String filterFullName(String fullName) {
+		if (fullName.startsWith("BOOT-INF.classes.")) {
 			fullName = fullName.substring(17);
 		}
 		return fullName;
@@ -73,19 +150,27 @@ public class ClassScanner {
 
 	private static List<String> scanJarFile(URL url) {
 		List<String> classes = new ArrayList<>();
-		try(ZipInputStream zis = new ZipInputStream(url.openStream())){
+		try (ZipInputStream zis = new ZipInputStream(url.openStream())) {
 			ZipEntry entry;
 			while ((entry = zis.getNextEntry()) != null) {
 				if (!entry.getName().contains("META-INF")) {
 					String className = entry.getName();
-					if (className.endsWith(".class") && !className.contains("$")) {
+					if (isClass(className)) {
 						classes.add(filterFullName(className.substring(0, className.length() - 6).replace("/", ".")));
 					}
 				}
 			}
-		}catch (IOException ignored){
+		} catch (IOException ignored) {
 
 		}
 		return classes;
 	}
+
+	private static boolean isClass(String className) {
+		return className.endsWith(".class") && !className.contains("$");
+	}
+
+	public static void main(String[] args) throws URISyntaxException {
+		scan().stream().filter(s -> s.startsWith("java.lang")).sorted().forEach(System.out::println);
+	}
 }