Java Bukkit从InputStream加载.jar文件



你好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)

最新更新