如何使用java黑魔法給一個entity生成getter,setter方法? java
因爲java是一門靜態語言,要給一個類動態添加方法,看似是不可能的。但牛B的程序員會讓任何事情發生。我只知道有兩種方式能夠作到,一種是字節碼增強,藉助asm包;另外一種是運行期增強,藉助javassist包。下面,嘗試用第二種方法,完成一個簡單的demo。 c++
大體思路以下:先在Filter類裏掃描工程獲得全部實體類,經過建立自定義類加載器加載實體類 ,在加載的過程當中經過javassist給每一個實體類添加getter setter。 程序員
爲何要自定義類加載器呢? 算法
咱們知道,全部的類都是經過類加載器加載到內存中,類加載器的加載經過它父加載器完成。java類加載器包括: app
一、啓動加載器(Bootstrap ClassLoader),祖宗輩的,由c++語言實現,是jvm一部分,負責加載JAVA_HOME\lib目錄中而且能被虛擬機識別的類庫。 jvm
二、擴展類加載器(Extension ClassLoader),爺爺輩的,負責加載JAVA_HOME\lib\ext目錄中的類庫。 ide
三、應用程序類加載器(Application ClassLoader),dady輩的,負責加載用戶類路徑(Classpath)上所指定的類庫,若是應用程序中沒有自定義過本身的類加載器,通常狀況下這個就是程序中默認的類加載器。 this
四、自定義類加載器。 spa
若是咱們使用app類加載器,就無法在加載類的時候給類動手腳了。若是咱們把內存中的類當成一張藍圖,一旦這張藍圖生成,咱們就更無法修改了。因此咱們須要自定義加載器,在生成藍圖以前就動手動腳。 .net
第一步:建立Filter
public class LoaderFilter implements Filter{ @Override public void destroy() { } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { MyClassLoader loader=new MyClassLoader(); //自定義加載器 //搜索文件路徑 List<String> classFileList = ClassSearcher.findFiles(ClassSearcher.classPathUrl.getFile(),"*.class"); for(String str:classFileList){ System.out.println(str); if(str.startsWith("com.kyle.entity")){ //屬於實體包下,則添加get,set loader.loadClass(str); } } chain.doFilter(req, resp); } @Override public void init(FilterConfig arg0) throws ServletException { } }
第二步:建立類加載器。javassist操做和java反射API操做差很少。
public class MyClassLoader extends ClassLoader{ @Override public Class<?> loadClass(String name) { try { InputStream is = getClass().getResourceAsStream(getPath(name)); if(is==null){ return super.loadClass(name); } ClassPool pool=ClassPool.getDefault(); CtClass clazz=pool.makeClass(is); CtField[] fields= clazz.getDeclaredFields(); System.out.println(Arrays.toString(fields)); for(CtField field:fields){ //add getter method System.out.println("filedname:"+field.getName()+",type:"+field.getType().getName()); String fieldname=upperFirst(field.getName()); CtMethod getter=new CtMethod(pool.get(field.getType().getName()), "get"+fieldname,null, clazz); getter.setModifiers(Modifier.PUBLIC); //訪問權限 getter.setBody("{ return this."+field.getName()+"; }"); clazz.addMethod(getter); //add setter method CtMethod setter=new CtMethod(CtClass.voidType, "set"+fieldname, new CtClass[]{pool.get(field.getType().getName())}, clazz); setter.setModifiers(Modifier.PUBLIC); setter.setBody("{this."+field.getName()+"=$1;}"); clazz.addMethod(setter); } return clazz.toClass(); } catch (Exception e) { throw new RuntimeException(e); } } private String getPath(String name){ name=name.replace(".", "/"); return "/"+name+".class"; } private String upperFirst (String str){ return str.substring(0,1).toUpperCase()+str.substring(1); }尋找類文件類classSearcher代碼:
public class ClassSearcher { public static URL classPathUrl = ClassSearcher.class.getResource("/"); static String lib = new File(classPathUrl.getFile()).getParent() + "/lib/"; /** * 遞歸查找文件 * * @param baseDirName * 查找的文件夾路徑 * @param targetFileName * 須要查找的文件名 */ public static List<String> findFiles(String baseDirName,String targetFileName) { /** * 算法簡述: 從某個給定的需查找的文件夾出發,搜索該文件夾的全部子文件夾及文件, * 若爲文件,則進行匹配,匹配成功則加入結果集,若爲子文件夾,則進隊列。 隊列不空,重複上述操做,隊列爲空,程序結束,返回結果。 */ List<String> classFiles = new ArrayList<String>(); String tempName = null; // 判斷目錄是否存在 File baseDir = new File(baseDirName); if (!baseDir.exists() || !baseDir.isDirectory()) { System.err.println("search error:" + baseDirName + "is not a dir!"); } else { String[] filelist = baseDir.list(); for (int i = 0; i < filelist.length; i++) { File readfile = new File(baseDirName + File.separator + filelist[i]); if (!readfile.isDirectory()) { tempName = readfile.getName(); if (ClassSearcher.wildcardMatch(targetFileName, tempName)) { String classname; String tem = readfile.getAbsoluteFile().toString().toString().replaceAll("\\\\", "/"); classname = tem.substring(tem.indexOf("/classes")+ "/classes".length(), tem.indexOf(".class")); if (classname.startsWith("/")) { classname = classname.substring(classname.indexOf("/") + 1); } classname = className(classname, "/classes"); classFiles.add(classname); } } else if (readfile.isDirectory()) { classFiles.addAll(findFiles(baseDirName + File.separator+ filelist[i], targetFileName)); } } } return classFiles; } /** * 查找jar包中的class * * @param baseDirName * jar路徑 * @param includeJars * @param jarFileURL * jar文件地址 <a href="http://my.oschina.net/u/556800" * target="_blank" rel="nofollow">@return</a> */ public static List<String> findjarFiles(String baseDirName, final List<String> includeJars) { List<String> classFiles = new ArrayList<String>(); try { // 判斷目錄是否存在 File baseDir = new File(baseDirName); if (!baseDir.exists() || !baseDir.isDirectory()) { System.out.println("file serach error:" + baseDirName + "is not a dir!"); } else { String[] filelist = baseDir.list(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return includeJars.contains(name); } }); for (int i = 0; i < filelist.length; i++) { JarFile localJarFile = new JarFile(new File(baseDirName + File.separator + filelist[i])); Enumeration<JarEntry> entries = localJarFile.entries(); while (entries.hasMoreElements()) { JarEntry jarEntry = entries.nextElement(); String entryName = jarEntry.getName(); if (!jarEntry.isDirectory()&&entryName.endsWith(".class")) { String className = entryName.replaceAll("/", ".") .substring(0, entryName.length() - 6); classFiles.add(className); } } localJarFile.close(); } } } catch (IOException e) { e.printStackTrace(); } return classFiles; } @SuppressWarnings("rawtypes") public static List<Class> findInClasspathAndJars(Class clazz, List<String> includeJars) { List<String> classFileList = findFiles(classPathUrl.getFile(),"*.class"); classFileList.addAll(findjarFiles(lib,includeJars)); return extraction(clazz,classFileList); } @SuppressWarnings("rawtypes") private static List<Class> extraction(Class clazz,List<String> classFileList) { List<Class> classList = new ArrayList<Class>(); for (String classFile : classFileList) { try { Class classInFile = Class.forName(classFile); if (clazz.isAssignableFrom(classInFile)) { // if (BeanKit.isSuperclass(classInFile,clazz)) { classList.add(classInFile); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } return classList; } private static String className(String classFile, String pre) { String objStr = classFile.replaceAll("\\\\", "/"); return objStr.replaceAll("/", "."); } /** * 通配符匹配 * * @param pattern * 通配符模式 * @param str * 待匹配的字符串 <a href="http://my.oschina.net/u/556800" * target="_blank" rel="nofollow">@return</a> * 匹配成功則返回true,不然返回false */ private static boolean wildcardMatch(String pattern, String str) { int patternLength = pattern.length(); int strLength = str.length(); int strIndex = 0; char ch; for (int patternIndex = 0; patternIndex < patternLength; patternIndex++) { ch = pattern.charAt(patternIndex); if (ch == '*') { // 通配符星號*表示能夠匹配任意多個字符 while (strIndex < strLength) { if (wildcardMatch(pattern.substring(patternIndex + 1), str.substring(strIndex))) { return true; } strIndex++; } } else if (ch == '?') { // 通配符問號?表示匹配任意一個字符 strIndex++; if (strIndex > strLength) { // 表示str中已經沒有字符匹配?了。 return false; } } else { if ((strIndex >= strLength) || (ch != str.charAt(strIndex))) { return false; } strIndex++; } } return (strIndex == strLength); } public static List<Class> findInClasspath(Class clazz) { List<String> classFileList = findFiles(classPathUrl.getFile(),"*.class"); return extraction(clazz,classFileList); }