Javassist - 如何将方法注入(inject) JAR 中的类

标签 java jar

我正在从 JAR 文件中读取一个类并注入(inject)一个函数。我如何将其写回 JAR 文件?

     // Load the class representation

   ClassPool pool = ClassPool.getDefault();
   pool.insertClassPath( "c:/Test.jar" );
   CtClass cc = pool.get("com.test.TestFunction"); 
   CtMethod m = CtNewMethod.make("public void test2() { System.out.println(\"test2\"); }", cc);
   cc.addMethod(m); 
   CtMethod cm = cc.getDeclaredMethod("test1", new CtClass[0]);
   cm.insertBefore("{ test2();}");
   cc.writeFile("c:/Test.jar");  // Fails here

线程“main”中的异常java.io.FileNotFoundException:c:\Test.jar\com\test\TestFunction.class(系统找不到指定的路径)

最佳答案

我想 Javassist 中没有简单的方法可以更新 JAR 并将更新的类替换为新类。所以我创建了一个 JarHandler 类,它只接收参数。

这是执行注入(inject)的主类

  public static void main(String args[]){
  ClassPool pool = ClassPool.getDefault();
  pool.insertClassPath( "c:/Test.jar" );
  CtClass cc = pool.get("com.test.TestFunction"); 
  CtMethod m = CtNewMethod.make("public void test2() { System.out.println(\"test2\"); }", cc);
 cc.addMethod(m); 
 CtMethod cm = cc.getDeclaredMethod("test1", new CtClass[0]);
 cm.insertBefore("{ test2();}");

 byte[] b = cc.toBytecode(); // convert the new class to bytecode.
 pool.removeClassPath(cp);   // need to remove the classpath to release connection to JAR file so we can update it.
 JarHandler jarHandler = new JarHandler();
 jarHandler.replaceJarFile("C:/Test.jar", b, "com/test/TestFunction.class");

 }

这是 JarHandler 类

 public class JarHandler{
   public void replaceJarFile(String jarPathAndName,byte[] fileByteCode,String fileName) throws IOException {
      File jarFile = new File(jarPathAndName);
      File tempJarFile = new File(jarPathAndName + ".tmp");
      JarFile jar = new JarFile(jarFile);
      boolean jarWasUpdated = false;

      try {
=
         JarOutputStream tempJar =
            new JarOutputStream(new FileOutputStream(tempJarFile));

         // Allocate a buffer for reading entry data.

         byte[] buffer = new byte[1024];
         int bytesRead;

         try {
            // Open the given file.

            try {
               // Create a jar entry and add it to the temp jar.

               JarEntry entry = new JarEntry(fileName);
               tempJar.putNextEntry(entry);
               tempJar.write(fileByteCode);

            } catch (Exception ex) {
                   System.out.println(ex);

                   // Add a stub entry here, so that the jar will close without an
                   // exception.

                   tempJar.putNextEntry(new JarEntry("stub"));
                }


            // Loop through the jar entries and add them to the temp jar,
            // skipping the entry that was added to the temp jar already.
            InputStream entryStream = null;
            for (Enumeration entries = jar.entries(); entries.hasMoreElements(); ) {
               // Get the next entry.

               JarEntry entry = (JarEntry) entries.nextElement();

               // If the entry has not been added already, so add it.

               if (! entry.getName().equals(fileName)) {
                  // Get an input stream for the entry.

                  entryStream = jar.getInputStream(entry);
                  tempJar.putNextEntry(entry);

                  while ((bytesRead = entryStream.read(buffer)) != -1) {
                     tempJar.write(buffer, 0, bytesRead);
                  }
               }else
                   System.out.println("Does Equal");
            }
            if(entryStream!=null)
                entryStream.close();
            jarWasUpdated = true;
         }
         catch (Exception ex) {
            System.out.println(ex);

            // IMportant so the jar will close without an
            // exception.

            tempJar.putNextEntry(new JarEntry("stub"));
         }
         finally {
            tempJar.close();
         }
      }
      finally {

         jar.close();

         if (! jarWasUpdated) {
            tempJarFile.delete();
         }
      }


      if (jarWasUpdated) {            
         if(jarFile.delete()){
           tempJarFile.renameTo(jarFile);
           System.out.println(jarPathAndName + " updated.");
         }else
             System.out.println("Could Not Delete JAR File");
      }
   }

这个函数只是通过将新的类字节码写入其中来创建一个临时 JAR。 然后遍历当前 JAR 的所有条目并将其所有条目写入临时文件 JAR 文件,除了正在更新的条目(字节码已经在上面写入)。然后它删除当前 JAR 并将其替换为使用相同 JAR 名称的临时 JAR。

关于Javassist - 如何将方法注入(inject) JAR 中的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22591903/

相关文章:

java - NoSuchAlgorithmException : der KeyStore not available

使用 JAR 文件中的类的 Java 程序

java - 将 shell 脚本转换为 jar 文件

java - 从 tomcat 访问 jar 文件

java - 是否有一个 JAR 可供 google-cloud-translate 使用 ANT 进行编译,而不是处理 40 多个单独的 JAR?

java - 使用 Eclipse 从 eBay 沙盒 WSDL 创建 stub 时出错

java - 在 Eclipse 中为现有代码生成 JavaDoc 注释

java - 用户按下键盘上的 Enter 键后禁用移动浏览器上的按钮

java - 哪种方法更适合在 sqlite 数据库中存储键值对?

java - 如何引用 JAR 文件中提供的 JSF 托管 bean?