The best you can do
You donβt need to use JarInputStream , as it adds manifest support to the ZipInputStream class, which we are not interested in here. You cannot cache your records (unless you directly store the contents of each record, which would be horrible in terms of memory consumption), because ZipInputStream not intended to be shared, therefore it cannot be read at the same time. The best you can do is store the name of the records in the cache, so that iterate over only the records when we know that the record exists.
The code could be something like this:
public class RemoteClassLoader extends ClassLoader { private final byte[] jarBytes; private final Set<String> names; public RemoteClassLoader(byte[] jarBytes) throws IOException { this.jarBytes = jarBytes; this.names = RemoteClassLoader.loadNames(jarBytes); } private static Set<String> loadNames(byte[] jarBytes) throws IOException { Set<String> set = new HashSet<>(); try (ZipInputStream jis = new ZipInputStream(new ByteArrayInputStream(jarBytes))) { ZipEntry entry; while ((entry = jis.getNextEntry()) != null) { set.add(entry.getName()); } } return Collections.unmodifiableSet(set); } ... @Override public InputStream getResourceAsStream(String name) {
The perfect solution
Accessing a zip record using a JarInputStream clearly not the way to do this, since you will need to iterate over the records to find which one is not a scalable approach , because performance will depend on the total number of records in your jar file.
To get the best results, you need to use ZipFile to access the record directly thanks to the getEntry(name) method, regardless of the size of your archive. Unfortunately, the ZipFile class ZipFile not provide any constructors that accept the contents of your archive as a byte array (this is not good practice, as you may encounter OOME if the file is too large), but only as a File , so you will need to change the logic of your class to save the contents of the zip to a temporary file, and then provide this temporary file to your ZipFile so that you can directly access the recording.
The code could be something like this:
public class RemoteClassLoader extends ClassLoader { private final ZipFile zipFile; public RemoteClassLoader(byte[] jarBytes) throws IOException { this.zipFile = RemoteClassLoader.load(jarBytes); } private static ZipFile load(byte[] jarBytes) throws IOException {
source share