我正在从 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/