你好Stackoverflow社区,
我有一个关于java和bukkit的问题。我有一个加密的插件,我不想把解密的文件保存在磁盘上。所以我使用了InputStream。但我现在的问题是如何将这个文件注入minecraft(bukkit)。有可用的自定义类加载器吗?我找了很多,但没有找到任何有效的解决方案。
我用AES-128:解密加密插件
FileInputStream fin;
CipherInputStream cin;
int nread = 0;
byte [] inbuf = new byte [MAX_FILE_BUF];
fin = new FileInputStream (input);
cin = new CipherInputStream (fin, mDecipher);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((nread = cin.read (inbuf)) > 0 )
{
byte[] trimbuf = new byte [nread];
for (int i = 0; i < nread; i++)
{
trimbuf[i] = inbuf[i];
}
baos.write(trimbuf);
}
所以现在我尝试用InputStream 加载文件
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream is2 = new ByteArrayInputStream(baos.toByteArray());
JarInputStream in = new JarInputStream(is2);
这在这一点上运行良好。现在我想把这个InputStream"is2"加载到bukkit服务器中。
因为类加载在java中的工作方式,所以不能像现在这样直接从输入流加载类。你能做的是:
- 将jar中的每个文件加载到内存中
- 使用从内存加载文件的自定义类加载器
- 使用该类加载器加载插件
第一步很简单,我们将为来自jar文件的文件制作一个Map<String,byte[]>
。
Map<String,byte[]> map = new HashMap<>();
ZipEntry entry;
byte[] read = new byte[1024];
while((entry = in.getNextEntry()) != null) {
ByteArrayOutputStream r = new ByteArrayOutputStream(Math.max(128, entry.getSize()));
int i;
while((i = in.read(read) >= 0)
r.write(read, 0, i);
is.close();
map.put(entry.getName(), r.toByteArray());
}
有了filename->byte数组的数据映射,我们就可以实现我们的自定义类加载器:
public class MappedJarClassLoader extends ClassLoader {
Map<String,byte[]> map = new HashMap<>();
public MappedJarClassLoader (ClassLoader parent, Map<String,byte[]> map) {
super(parent);
this.map = map;
}
public Class findClass(String name) throws ClassNotFoundException {
byte[] b = map.get(name.replace('/', '$').replace('.', File.separatorChar));
if(b == null)
throw new ClassNotFoundException(name);
return defineClass(name, b, 0, b.length);
}
}
由于bukkit中的限制,我们不能将类扩展JavaPlugin放置在jar的加密部分中。与其这样做,不如将一个类放在加密的jar中,该jar有一个接受主实例的构造函数,并使用:在onEnable中加载该类
mappedJarClassLoader.loadClass("path.to.new.class").getConstructor(getClass()).newInstance(this)