文档章节

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

绝望的八皮
 绝望的八皮
发布于 2012/07/22 20:10
字数 903
阅读 3697
收藏 3

 目前的的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

© 著作权归作者所有

绝望的八皮

绝望的八皮

粉丝 393
博文 22
码字总数 10505
作品 2
其它
CTO(技术副总裁)
私信 提问
加载中

评论(10)

weizc
weizc
maven启动时修改这个方法

private static String fileName(Class clazz) {
String controllerFile = System.getProperty("user.dir")+File.separator+"src";

if(isMaven) {
  controllerFile+=File.separator+"main" +File.separator+"java";
}

for (String temp : clazz.getName().split("\\.")) {
controllerFile = controllerFile+File.separator+temp;
}
return controllerFile+".java";
}
weizc
weizc
jdk1.5+
weizc
weizc
package com.jfinal.core;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
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🇲🇲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(ActionInvocationai){", 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<String>();
    int lineNum = 1;
    File file = new File(fileName);
    try {
      BufferedReader br=new BufferedReader(new FileReader(file));
      
      String instring;
      int i = 0;
      while ((instring = br.readLine()) != null) {
        i=i+1;
        if (codeFragment.equals(deleteWhitespace(instring))) {
          break;
        }

      }
      lineNum = i;
      

    } catch (IOException e) {
      e.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;
   }
}
绝望的八皮
绝望的八皮 博主

引用来自“本人纯属虚构”的评论

博主和詹波都值得我们学习啊 向你们致敬

目前我的实践是,建了一个jfinal-util的源码目录,导入了这个源码,然后ant脚本中编译和打包的时候忽略掉
本人纯属虚构
本人纯属虚构
博主和詹波都值得我们学习啊 向你们致敬
JFinal
JFinal

引用来自“绝望的八皮”的评论

引用来自“JFinal”的评论

如果要更好的实现,目前能想到的办法是,利用 ecj 编译出来的字节码的特点来分析 class 文件来得源码精确行号。但这样做有两个缺点:二是只能使用 ecj 来编译,二是字节码要含 debug信息,总的来说暂没想到完美的实现

嗯我第一个想法也是分析字节码得到行号,但是对这方面的东西不太熟悉。没想到方案

或许有完美的方案,重在创新
绝望的八皮
绝望的八皮 博主

引用来自“JFinal”的评论

如果要更好的实现,目前能想到的办法是,利用 ecj 编译出来的字节码的特点来分析 class 文件来得源码精确行号。但这样做有两个缺点:二是只能使用 ecj 来编译,二是字节码要含 debug信息,总的来说暂没想到完美的实现

嗯我第一个想法也是分析字节码得到行号,但是对这方面的东西不太熟悉。没想到方案
JFinal
JFinal
如果要更好的实现,目前能想到的办法是,利用 ecj 编译出来的字节码的特点来分析 class 文件来得源码精确行号。但这样做有两个缺点:二是只能使用 ecj 来编译,二是字节码要含 debug信息,总的来说暂没想到完美的实现
绝望的八皮
绝望的八皮 博主

引用来自“JFinal”的评论

JFinal ActionReporter 在当时设计源码定位功能时打算设计成精确定位,因为性能与简洁的考虑暂不实现。你目前能想到这个方向非常不错,但实现还不够完美。以后有时间了我可能会再想想别的办法。你目前的实现可以稍微改进一下,就是把 Controller 改为 Action, 把 Method 去掉,源码定位时直接定位到 Controller 中的 action 中

嗯。这么的消耗是太大了,我再琢磨琢磨~
JFinal
JFinal
JFinal ActionReporter 在当时设计源码定位功能时打算设计成精确定位,因为性能与简洁的考虑暂不实现。你目前能想到这个方向非常不错,但实现还不够完美。以后有时间了我可能会再想想别的办法。你目前的实现可以稍微改进一下,就是把 Controller 改为 Action, 把 Method 去掉,源码定位时直接定位到 Controller 中的 action 中
JFinal 1.0.9 发布,Java 极速WEB+ORM框架

JFinal 1.0.9 进行了诸多优化,添加了一些小的实用功能,去掉了一些多余的功能,其它变化如下: 1:DbKit.setDataSource(DataSource) 改为public 可见性,方便使用多数据源时切换数据源 2:D...

JFinal
2012/07/10
1K
49
JFinal Extensions

Jfinal-ext是对java极速web框架 jfinal 的一个扩充,主要利用jfinal微内核高扩展的特性扩展常用的实用功能和集成各种第三方框架,简化开发者的学习应用成本,为您节约更多时间,去陪恋人、家...

绝望的八皮
2012/10/10
41.6K
50
JFinal 1.1.0 发布,Java 极速WEB+ORM框架

JFinal 1.1.0 进行了诸多优化,添加了一些小的实用功能,去掉了一些多余的功能,其它变化如下: 1:添加 com.jfinal.plugin.activerecord.tx.TxByRegex 与 TxByActionKeys,分别支持正则声明...

JFinal
2012/07/17
1K
37
Linux下Hadoop Eclipse插件编译安装

转载自:http://www.cnblogs.com/kinuxroot/archive/2013/05/06/linuxhadoopeclipse_plugin.html 在RedHat,hadoop1.1.2下测试通过。有些地方注明详细了。 刚刚开始研究Hadoop,在写Map Red...

kartik
2014/05/04
0
0
在Eclipse RCP中实现反转控制(IoC)

Eclipse富客户平台(RCP)是一个功能强大的软件平台,它基于插件间的互连与协作,允许开发人员构建通用的应用程序。RCP使开发人员可以集中精力进行应用程序业务代码的开发,而不需要花费时间重...

雪中漫步
2010/03/29
521
0

没有更多内容

加载失败,请刷新页面

加载更多

64.监控平台介绍 安装zabbix 忘记admin密码

19.1 Linux监控平台介绍 19.2 zabbix监控介绍 19.3/19.4/19.6 安装zabbix 19.5 忘记Admin密码如何做 19.1 Linux监控平台介绍: 常见开源监控软件 ~1.cacti、nagios、zabbix、smokeping、ope...

oschina130111
昨天
64
0
当餐饮遇上大数据,嗯真香!

之前去开了一场会,主题是「餐饮领袖新零售峰会」。认真听完了餐饮前辈和新秀们的分享,觉得获益匪浅,把脑子里的核心纪要整理了一下,今天和大家做一个简单的分享,欢迎感兴趣的小伙伴一起交...

数澜科技
昨天
26
0
DNS-over-HTTPS 的下一代是 DNS ON BLOCKCHAIN

本文作者:PETER LAI ,是 Diode 的区块链工程师。在进入软件开发领域之前,他主要是在做工商管理相关工作。Peter Lai 也是一位活跃的开源贡献者。目前,他正在与 Diode 团队一起开发基于区块...

红薯
昨天
43
0
CC攻击带来的危害我们该如何防御?

随着网络的发展带给我们很多的便利,但是同时也带给我们一些网站安全问题,网络攻击就是常见的网站安全问题。其中作为站长最常见的就是CC攻击,CC攻击是网络攻击方式的一种,是一种比较常见的...

云漫网络Ruan
昨天
27
0
实验分析性专业硕士提纲撰写要点

为什么您需要研究论文的提纲? 首先当您进行研究时,您需要聚集许多信息和想法,研究论文提纲可以较好地组织你的想法, 了解您研究资料的流畅度和程度。确保你写作时不会错过任何重要资料以此...

论文辅导员
昨天
44
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部