没有.java 源程序 的情况下修改代码

有时,我们只有.jar 文件而无法得到获取源码(.java),但又需要对代码进行修改,这时可以考虑以下几种方法:

一、.jar 文件反编译成.java ,构建工程,修改后,再生成.jar

对于比较复杂的项目,这种方法是非常困难的,因为反编译之后或多或少会与源码有不同,并且涉及refer 一些库,以及原编译工具的版本问题,所以,要想真正恢复源代码,需要一些时间。

推荐反编译工具 jd-gui,C++编写的小工具,简单,方便https://github.com/java-decompiler/jd-gui/releases

二、直接修改.class 

1、修改.class的方法网上有许多,如使用一些工具直接修改等,但最终本人使用Javassist 获得了成功。

我们知道 Java 字节码以二进制的形式存储在 class 文件中,每一个 class 文件包含一个 Java 类或接口。Javassist 就是一个用来处理 Java 字节码的类库。

import java.io.IOException;

import javassist.*;
import javassist.ClassPool;
 
public class InsertCodeToMethod {
    private static final boolean True = false;
	public static void main(String args[]) throws NotFoundException, CannotCompileException, IOException{
        //获取class文件
    	ClassPool cPool = new ClassPool(true);
    	cPool.insertClassPath("C:\\Users\\503061752\\Desktop\\New folder (3)");
    	cPool.importPackage("com.ge.dspmicro.robot.subscriptionmachineadapter.RobotSubscriptionListener");
    	
		//获取该class对象
		CtClass clas = cPool.get("com.ge.dspmicro.robot.subscriptionmachineadapter.RobotSubscriptionMachineAdapterImpl");      
        if(clas==null){
               //方法未找到
            System.out.println("classname "+clas+" not found");
        }else{
            insertToLine(clas,"initrobotstatus");
       
            clas.writeFile();
          //替换原有的文件,必须写,否则文件不更新
            clas.writeFile("C:\\Users\\503061752\\Desktop\\New folder (3)");
        }  
    }
    public static void insertToLine (CtClass ccl,String method) throws NotFoundException, CannotCompileException{
        //获取方法信息,如果方法不存在,则抛出异常
        CtMethod ctMethod = ccl.getDeclaredMethod(method); 
        ctMethod.insertAt(576,true,"discrete_readaddr.put(\"PhmHotISO\", Integer.valueOf(23));\n");
    }
    }    

以上是示例代码,主要记录一下过程中的坑:

(1)    必须使用 clas.writeFile("C:\\Users\\503061752\\Desktop\\New folder (3)");更新原java 文件

(2)  编译报错,如找不到某class 或把引用类的成员变量认成class,且不能识别,考虑是否可以用cPool.importPackage 显示的把外部类导入

(3) 对于范型符号需要特殊处理,否则程序编译报错

如"Map tags = new HashMap<>();"报错时可以试着写成"java.util.Map/**/ tags = new java.util.HashMap/*<>*/();"

"J1-1554-003 " 写成\"J1-1554-003\"

(4) javassist 接口查询 https://www.javassist.org/html/javassist/CtBehavior.html

void insertAfter​(java.lang.String src)

Inserts bytecode at the end of the body.

void insertAfter​(java.lang.String src, boolean asFinally)

Inserts bytecode at the end of the body.

int insertAt​(int lineNum, boolean modify, java.lang.String src)

Inserts bytecode at the specified line in the body.

int insertAt​(int lineNum, java.lang.String src)

Inserts bytecode at the specified line in the body.

void insertBefore​(java.lang.String src)

Inserts bytecode at the beginning of the body.

void setBody​(java.lang.String src)

Sets a method/constructor body.

void setBody​(java.lang.String src, java.lang.String delegateObj, java.lang.String delegateMethod)

Sets a method/constructor body.

(5) 换行格式   + " this.phm_sn.put(Short.valueOf((short)113), \"J1-1550-002\");"

(6)不能写成ctMethod.insertAt(240,true,"this.phm_sn.put((short)22, \"J2-1241-001\");\n");

         应写成ctMethod.insertAt(240,true,"this.phm_sn.put(Short.valueOf((short)22), \"J2-1241-001\");\n");

       否则报错:Exception in thread "main" javassist.CannotCompileException: [source error] put(short,java.lang.String) not     found in java.util.Map

使用体会,javassist 有自己的一些小规则,只能对.class 进行简单的修改,如果涉及逻辑变动,最好还是修改源码

2、简单的类也可以直接反编译成.java 源码,用eclipse 修改,然后自动更新生成.class。但稍微复杂一些,便会编译错误。

你可能感兴趣的:(.class,javassist,java)