[英]Load classes from jar file in sub-folder in zip file
我有一個具有以下結構的 zip 文件
plugin
data
abc.jar
xyz.jar
我想使用這些 jars 創建一個 URLClassLoder 實例。 一種方法是對該文件進行 uzip,然后使用該文件系統路徑來創建 URLClassLoaders。 我可以在內存中做同樣的事情嗎?
好的,您可以檢查此答案https://stackoverflow.com/a/2614154/90313
您可以一起使用它們來實現所需的功能。
以下是工作解決方案。 您可以根據您的要求進行修改。
zip解壓參考: 在內存中遞歸解壓縮存檔
類加載參考: Java:如何將存儲為 byte[] 的類加載到 JVM 中?
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public final class ZippedJarClassReader {
private final static String JAR_EXTENSION = ".jar";
public static Map<String, byte[]> loadZip(final File file) throws IOException {
final byte[] bytes = Files.readAllBytes(file.toPath());
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(bytes);
return unzip(baos);
}
public static final Map<String, byte[]> unzip(final ByteArrayOutputStream baos) {
final Map<String, byte[]> result = new HashMap<String, byte[]>();
try(final ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(baos.toByteArray()))) {
ZipEntry entry;
while ((entry = in.getNextEntry()) != null) {
final ByteArrayOutputStream os = new ByteArrayOutputStream();
if (!entry.isDirectory()) {
os.write(in.readAllBytes());
if (entry.getName().toLowerCase().endsWith(JAR_EXTENSION)) {
result.putAll(unzip(os));
} else if (entry.getName().toLowerCase().endsWith(".class")) {
result.put(entry.getName().replaceAll("/", ".").substring(0, entry.getName().length() - 6), os.toByteArray());
}
}
}
return result;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;
public final class ZipClassLoader extends URLClassLoader {
private final Map<String, byte[]> classes;
public ZipClassLoader(URL[] urls, final File zipFile) throws IOException {
super(urls);
classes = ZippedJarClassReader.loadZip(zipFile);
}
@Override
public final Class<?> findClass(String name) throws ClassNotFoundException {
final byte[] bytes = classes.get(name);
if(bytes != null) return defineClass(name, bytes, 0, bytes.length);
return super.findClass(name);
}
}
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.zip.ZipException;
public class Test {
@SuppressWarnings("resource")
public static void main(String[] args) throws ZipException, IOException, ClassNotFoundException {
final File zipFile = new File("zipfile.zip");
final URLClassLoader loader = new ZipClassLoader(new URL[] {}, zipFile);
final Class<?> classz = loader.loadClass("org.util.nanolog.Test");
System.out.println(classz);
}
}
好的, jar:
URI 方案似乎不起作用,但是 nio 可以。 這是加載 Jetifier(Android 構建工具)而不解壓縮所有內容的示例。
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.FileSystem;
import java.security.SecureClassLoader;
import static java.nio.file.FileSystems.newFileSystem;
import static java.nio.file.Files.list;
import static java.nio.file.Files.readAllBytes;
import static java.nio.file.Paths.get;
class Scratch {
public static void main(String[] args) throws Exception {
String applicationZip = "/home/mike/Downloads/jetifier-standalone.zip";
String pathToJars = "/jetifier-standalone/lib/";
String mainClassName = "com.android.tools.build.jetifier.standalone.Main";
FileSystem zip = newFileSystem(get(applicationZip));
FileSystem[] jars = list(zip.getPath(pathToJars))
.map(jar -> {
try { return newFileSystem(jar); }
catch (IOException e) { throw new UncheckedIOException(e); }
})
.toArray(FileSystem[]::new);
new SecureClassLoader(Scratch.class.getClassLoader()) {
@Override protected Class<?> findClass(String name)
throws ClassNotFoundException {
String fileName = '/' + name.replace('.', '/') + ".class";
for (FileSystem jar : jars) {
try {
byte[] bytes = readAllBytes(jar.getPath(fileName));
return defineClass(name, bytes, 0, bytes.length);
} catch (IOException ignored) {
}
}
throw new ClassNotFoundException(name);
}
}.loadClass(mainClassName)
.getMethod("main", String[].class)
.invoke(null, new Object[] { new String[0] });
}
}
這有效並成功地從 Jetifier 打招呼。 我使用 JDK 13。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.