加强版ActionReporter,提升eclipse源代码定位功能

原创
2012/07/22 20:10
阅读数 4.2K

 目前的的ActionReporter可以定位到当前方法调用过的Controller,点击eclipse控制台中的链接可以定位到改类的第一行,但是并不能直接定位到调用方法的那一行。

为了进一步提供开发者的体验,我加强了ActionReporter的源代码定位功能,能直接定位到调用的方法上面。先看下面效果图。 

 

当请请求调用了MobileBindController的heart方法,控制可以直接打出heart方法在 MobileBindController.java中的行数。

在java代码中虽然有能得到当前方法栈上的代码行数,但是由于jfinal中的aop并没有使用第三方的字节码工具修改原类的字节码,所有没有办法在方法调用之前知道要调用方法的行数。如果使用spring aop可以把这个功能切到目标方法调用的前面,应该可以达到效果。(没实际操作过还..)

在不修改字节码的情况下,我暂时只想到利用源码来计算行数..反正都是开发阶段,这样其实也无大碍..原理很简单.得到调用的类和方法然后到对应源文件去找该方法的字符串所在行。实现不够优雅但是功能还是挺实用的。

代码中删除字符串空格的方法直接copy自commons-lang。

代码再jdk7下编写的。7以下的需要把遍历文件那段代码稍微替换以下就ok了。

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中同名的此类。

在类加载的时候classes会在lib之前加载,所以类加载器中加载的是我们改写过后的com.jfinal.core.ActionReporter

展开阅读全文
加载中
点击加入讨论🔥(10) 发布并加入讨论🔥
10 评论
3 收藏
2
分享
返回顶部
顶部