1. 程式人生 > >Javassist生成class(生成類,方法,欄位,註解)

Javassist生成class(生成類,方法,欄位,註解)

最近接觸了下javassist,試著進行位元組碼操縱,javassist的上手還是比較簡單,官方文件說的很詳細,而且例子也給的蠻多。
傳送門:Javassist官方文件地址

下面是自己寫的一個方法,其中生成了一個經典的Spring的controller類。具體寫法如下,程式碼已經貼上了註釋。

public void makeclass(String className,String methodName, CONSTANTS.INVOKETYPE invoketype,String interfaceCode) throws NotFoundException, CannotCompileException, IOException {
        ClassPool pool = ClassPool.getDefault
(); CtClass clazz = pool.makeClass(className); ClassFile ccFile = clazz.getClassFile(); ConstPool constpool = ccFile.getConstPool(); CtClass executor = pool.get("com.javassist.test.Executor"); CtClass requst = pool.get("javax.servlet.http.HttpServletRequest");
CtClass response = pool.get("javax.servlet.http.HttpServletResponse"); String fieldName = invoketype.getValue()); // 增加欄位 CtField field = new CtField(executor,fieldName,clazz); field.setModifiers(Modifier.PUBLIC); FieldInfo fieldInfo = field.getFieldInfo
(); // 屬性附上註解 AnnotationsAttribute fieldAttr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag); Annotation autowired = new Annotation("org.springframework.beans.factory.annotation.Autowired",constpool); fieldAttr.addAnnotation(autowired); fieldInfo.addAttribute(fieldAttr); clazz.addField(field); // 增加方法,javassist可以直接將字串set到方法體中,所以使用時非常方便 CtMethod method = new CtMethod(new CtClassType(CtClass.javaLangObject,pool),methodName,new CtClass[]{requst,response},clazz); method.setModifiers(java.lang.reflect.Modifier.PUBLIC); StringBuffer methodBody = new StringBuffer(); methodBody.append("{return "+fieldName+".execute(\""+interfaceCode+"\",(com.javassist.test.RequestVo)$1.getAttribute(\"request\"));}"); method.setBody(methodBody.toString()); // 類附上註解 AnnotationsAttribute classAttr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag); Annotation controller = new Annotation("org.springframework.stereotype.Controller",constpool); Annotation requestMapping = new Annotation("org.springframework.web.bind.annotation.RequestMapping.RequestMapping",constpool); String visitPath = "/api/department"; requestMapping.addMemberValue("value",new StringMemberValue(visitPath,constpool)); classAttr.addAnnotation(controller); classAttr.addAnnotation(requestMapping); ccFile.addAttribute(classAttr); //方法附上註解 AnnotationsAttribute methodAttr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag); //Annotation annotation3 = new Annotation("org.springframework.web.bind.annotation.RequestMapping.RequestMapping",constpool); requestMapping.addMemberValue("value",new StringMemberValue("/register",constpool)); Annotation responseBody = new Annotation("org.springframework.web.bind.annotation.RequestMapping.ResponseBody",constpool); methodAttr.addAnnotation(requestMapping); methodAttr.addAnnotation(responseBody); MethodInfo info = method.getMethodInfo(); info.addAttribute(methodAttr); clazz.addMethod(method); clazz.writeFile(); }

需要注意的是,
1,執行在web容器或者Jboss下可能會出現找不到類,很有可能是類搜尋路徑的問題,可以通過增加搜尋路徑在試著解決問題,pool.insertClassPath(new ClassClassPath(this.getClass()));。
2,執行在web容器或者Jboss下可能會出現類載入器問題,報ClassCastException,可以不使用預設的類載入器,也可以自定義類載入器進行載入。