增強版ActionReporter,提高eclipse源代碼定位功能

 目前的的ActionReporter能夠定位到當前方法調用過的Controller,點擊eclipse控制檯中的連接能夠定位到改類的第一行,可是並不能直接定位到調用方法的那一行。java

爲了進一步提供開發者的體驗,我增強了ActionReporter的源代碼定位功能,能直接定位到調用的方法上面。先看下面效果圖。 spring

 

當請請求調用了MobileBindController的heart方法,控制能夠直接打出heart方法在 MobileBindController.java中的行數。app

在java代碼中雖然有能獲得當前方法棧上的代碼行數,可是因爲jfinal中的aop並無使用第三方的字節碼工具修改原類的字節碼,全部沒有辦法在方法調用以前知道要調用方法的行數。若是使用spring aop能夠把這個功能切到目標方法調用的前面,應該能夠達到效果。(沒實際操做過還..)eclipse

在不修改字節碼的狀況下,我暫時只想到利用源碼來計算行數..反正都是開發階段,這樣其實也無大礙..原理很簡單.獲得調用的類和方法而後到對應源文件去找該方法的字符串所在行。實現不夠優雅可是功能仍是挺實用的。工具

代碼中刪除字符串空格的方法直接copy自commons-lang。ui

代碼再jdk7下編寫的。7如下的須要把遍歷文件那段代碼稍微替換如下就ok了。url

package com.jfinal.core;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import com.jfinal.aop.Interceptor;

/**
 * ActionReporter
 */
final class ActionReporter {
	
	private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	
	/**
	 * Report action before action invoking when the common request coming
	 */
	static final boolean reportCommonRequest(Controller controller, Action action) {
		String content_type = controller.getRequest().getContentType();
		if (content_type == null || content_type.toLowerCase().indexOf("multipart") == -1) {	// if (content_type == null || content_type.indexOf("multipart/form-data") == -1) {
			doReport(controller, action);
			return false;
		}
		return true;
	}
	
	/**
	 * Report action after action invoking when the multipart request coming
	 */
	static final void reportMultipartRequest(Controller controller, Action action) {
		doReport(controller, action);
	}
	
	private static final void doReport(Controller controller, Action action) {
		StringBuilder sb = new StringBuilder("\nJFinal action report -------- ").append(sdf.format(new Date())).append(" ------------------------------\n");
		Class<? extends Controller> cc = action.getControllerClass();
		sb.append("Controller  : ").append(cc.getName()).append(".(").append(cc.getSimpleName()).append(".java:")
		  .append(lineNum("publicvoid"+action.getMethodName()+"(){", fileName(cc))).append(")");
		sb.append("\nMethod      : ").append(action.getMethodName()).append("\n");
		
		String urlParas = controller.getPara();
		if (urlParas != null) {
			sb.append("UrlPara     : ").append(urlParas).append("\n");
		}
		
		Interceptor[] inters = action.getInterceptors();
		if (inters.length > 0) {
			sb.append("Interceptor : ");
			for (int i=0; i<inters.length; i++) {
				if (i > 0)
					sb.append("\n              ");
				Interceptor inter = inters[i];
				Class<? extends Interceptor> ic = inter.getClass();
				sb.append(ic.getName()).append(".(").append(ic.getSimpleName()).append(".java:")
				  .append(lineNum("publicvoidintercept", fileName(inter.getClass()))).append(")");
			}
			sb.append("\n");
		}
		
		// print all parameters
		HttpServletRequest request = controller.getRequest();
		@SuppressWarnings("unchecked")
		Enumeration<String> e = request.getParameterNames();
		if (e.hasMoreElements()) {
			sb.append("Parameter   : ");
			while (e.hasMoreElements()) {
				String name = e.nextElement();
				String[] values = request.getParameterValues(name);
				if (values.length == 1) {
					sb.append(name).append("=").append(values[0]);
				}
				else {
					sb.append(name).append("[]={");
					for (int i=0; i<values.length; i++) {
						if (i > 0)
							sb.append(",");
						sb.append(values[i]);
					}
					sb.append("}");
				}
				sb.append("  ");
			}
			sb.append("\n");
		}
		sb.append("--------------------------------------------------------------------------------\n");
		System.out.print(sb.toString());
	}

	private static String fileName(Class clazz) {
		String controllerFile = System.getProperty("user.dir")+File.separator+"src";
		for (String temp : clazz.getName().split("\\.")) {
			controllerFile = controllerFile+File.separator+temp;
		}
		return controllerFile+".java";
	}

	private static int lineNum(String codeFragment, String fileName) {
		List<String> lines = new ArrayList<>();
		int lineNum = 1;
		Path path = Paths.get(fileName);
		try {
			lines = Files.readAllLines(path, Charset.forName("utf-8"));
			for (int i = 0; i <lines.size(); i++) {
				String line = lines.get(i);
				if (codeFragment.equals(deleteWhitespace(line))) {
					lineNum=i+1;
					break;
				}
			}
		} catch(NoSuchFileException e1){
			// interceptor in jfinal.jar
		}
		catch (IOException e2) {
			e2.printStackTrace();
		}
		return lineNum;
	}
	
	 private static String deleteWhitespace(String str) {
	        if (isEmpty(str)) {
	            return str;
	        }
	        int sz = str.length();
	        char[] chs = new char[sz];
	        int count = 0;
	        for (int i = 0; i < sz; i++) {
	            if (!Character.isWhitespace(str.charAt(i))) {
	                chs[count++] = str.charAt(i);
	            }
	        }
	        if (count == sz) {
	            return str;
	        }
	        return new String(chs, 0, count);
	    }
	 
	 private static boolean isEmpty(CharSequence cs) {
	        return cs == null || cs.length() == 0;
	 }
}

 

 在目前官方jar中沒有采用次java類的狀況下,要使用這個功能的朋友請在本身的src下面創建com.jfinal.core包,放入和jar中同名的此類。spa

在類加載的時候classes會在lib以前加載,因此類加載器中加載的是咱們改寫事後的com.jfinal.core.ActionReportercode

相關文章
相關標籤/搜索