struts2让人感觉很别扭的一个地方:由于Action中的方法都是无参数的,真实的参数要么写在Action的实例变量中,要么从request中读取。
如果一个Action只写一个命令,这还没有什么问题,但为了避免Action类数量的膨胀,我们一般将一个CRUD操作都放在同一个Action类中,用action!method的方式来访问。这时候严重影响方法的可读性。不读完代码通常不知道某个Action的方法需要哪些参数传递给它。
action方法的返回值也存在同样问题。
有时候在想,如果struts2的拦截器能自动选择要执行的方法,并且按照方法的参数名称名称来匹配方法参数就好了。这儿的问题是如何获取到方法参数名称。
好,下面我们来看一下怎么获取方法的参数名称。
我们知道,仅仅从class运行的角度,方法参数名称是没有必要的,方法参数类似局部变量一样,也是按照在局部变量表的偏移位置进行访问。为了调试方便(?)javac在编译时可选将方法参数以及局部变量名称存放在class文件中对应方法的局部变量表LocalVariableTable中。
我们看一个不包含局部变量表的class文件的结构:
再看一下包含局部变量表的class文件结构:
要控制是否生成局部变量表,用javac –g参数选项:
在Eclipse中这样设置:
接下来借助于一款字节码工具来读取局部变量表信息。Javassist是东京工业大学Shigeru Chiba编写的开源的字节码工具包,相对于ASM,性能稍低,但可读性更好,如果用Struts2的话,它已经被包含在xwork-core.jar文件中,所以不需要额外导入了。
package my;
import java.util.Arrays;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
@SuppressWarnings("unchecked")
public class Hello {
public static void main(String[] args) throws Exception {
// 匹配静态方法
String[] paramNames = getMethodParamNames(Hello.class, "main", String[].class);
System.out.println(Arrays.toString(paramNames));
// 匹配实例方法
paramNames = getMethodParamNames(Hello.class, "foo", String.class);
System.out.println(Arrays.toString(paramNames));
// 自由匹配任一个重名方法
paramNames = getMethodParamNames(Hello.class, "getMethodParamNames");
System.out.println(Arrays.toString(paramNames));
// 匹配特定签名的方法
paramNames = getMethodParamNames(Hello.class, "getMethodParamNames", Class.class, String.class);
System.out.println(Arrays.toString(paramNames));
}
/**
* 获取方法参数名称,按给定的参数类型匹配方法
*
* @param clazz
* @param method
* @param paramTypes
* @return
* @throws NotFoundException
* 如果类或者方法不存在
* @throws MissingLVException
* 如果最终编译的class文件不包含局部变量表信息
*/
public static String[] getMethodParamNames(Class clazz, String method, Class... paramTypes)
throws NotFoundException, MissingLVException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get(clazz.getName());
String[] paramTypeNames = new String[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++)
paramTypeNames[i] = paramTypes[i].getName();
CtMethod cm = cc.getDeclaredMethod(method, pool.get(paramTypeNames));
return getMethodParamNames(cm);
}
/**
* 获取方法参数名称,匹配同名的某一个方法
*
* @param clazz
* @param method
* @return
* @throws NotFoundException
* 如果类或者方法不存在
* @throws MissingLVException
* 如果最终编译的class文件不包含局部变量表信息
*/
public static String[] getMethodParamNames(Class clazz, String method) throws NotFoundException, MissingLVException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get(clazz.getName());
CtMethod cm = cc.getDeclaredMethod(method);
return getMethodParamNames(cm);
}
/**
* 获取方法参数名称
*
* @param cm
* @return
* @throws NotFoundException
* @throws MissingLVException
* 如果最终编译的class文件不包含局部变量表信息
*/
protected static String[] getMethodParamNames(CtMethod cm) throws NotFoundException, MissingLVException {
CtClass cc = cm.getDeclaringClass();
MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
if (attr == null)
throw new MissingLVException(cc.getName());
String[] paramNames = new String[cm.getParameterTypes().length];
int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
for (int i = 0; i < paramNames.length; i++)
paramNames[i] = attr.variableName(i + pos);
return paramNames;
}
/**
* 在class中未找到局部变量表信息<br>
* 使用编译器选项 javac -g:{vars}来编译源文件
*
* @author Administrator
*
*/
public static class MissingLVException extends Exception {
static String msg = "class:%s 不包含局部变量表信息,请使用编译器选项 javac -g:{vars}来编译源文件。";
public MissingLVException(String clazzName) {
super(String.format(msg, clazzName));
}
}
static void foo() {
}
void foo(String bar) {
}
}
运行结果如下:
[args]
[bar]
[clazz, method, paramTypes]
[clazz, method]
- 大小: 46.9 KB
- 大小: 51.1 KB
- 大小: 10.3 KB
- 大小: 64 KB
分享到:
相关推荐
在Java编程语言中,获取方法参数名称通常是一个挑战,因为Java的字节码(class文件)在编译时默认不保存参数的名称。然而,从Java 8开始,Java引入了一个新的特性,允许开发者在运行时通过反射获取方法参数的名称。...
在C#编程中,获取调用函数的参数名称和值是一项常见的需求,特别是在日志记录、调试或动态处理参数时。下面将详细讲解如何在C#中实现这一功能。 首先,我们要了解C#中的反射机制。反射是.NET框架提供的一种强大工具...
然而,要动态获取参数名称和值,我们需要利用反射(Reflection)和表达式树(Expression Trees)这两个强大的工具。 **反射(Reflection)**是.NET框架的一个特性,它允许程序在运行时检查自身的信息,如类型、属性...
在Java编程中,有时我们需要获取一个方法的参数名称,这对于日志记录、调试或动态代码生成等场景非常有用。然而,Java的常规运行时API并不直接提供这样的功能,因为参数名称在编译后的字节码中通常是不可见的。本文...
然后,我们可以通过调用`Parameter`对象的`getName()`方法来获取参数的名称。 以下是一个简单的示例,展示了如何使用Java 8获取方法参数名: ```java public class Test { public void exampleMethod(String ...
总结,Java解析WSDL文档获取方法与参数涉及到的技术点包括:了解WSDL的基本概念,使用Apache CXF或其他类似库,加载和解析WSDL文档,获取服务、端点、操作和消息信息,最后可能还需要生成Java客户端代码以便于调用...
其中 `name` 是我们要获取参数的名称。正则表达式中的 `i` 标志表示匹配时不区分大小写。 3. 使用 `match` 方法对窗口位置的查询字符串(即URL中“?”后的部分)进行匹配。 4. 如果匹配成功,`unescape` 函数用于将...
- **参数`name`**:表示要获取的查询参数名称。 - **正则表达式`reg`**:用于匹配查询字符串中特定参数的值。 - `(^|&)`: 匹配查询字符串的开头或“&”符号前的位置。 - `name`: 匹配传入的参数名。 - `=([^&]*)`...
本文将深入探讨Spring MVC请求处理方法的参数特性及其使用方式。 ### 1. 请求方法参数类型 Spring MVC支持多种类型的参数,包括基本数据类型、对象、数组、集合、Map以及自定义类型。例如: - **基本数据类型**:...
在命令行环境中,我们可以通过在程序名称后面添加参数来改变程序的行为。例如,"myprogram.exe -debug"可以启动程序并开启调试模式。对于桌面应用,虽然用户通常看不到命令行,但很多应用程序依然支持通过快捷方式的...
获取当前计算机的ID和预设参数配置文件;根据ID,从预设参数配置文件中匹配与ID对应的配置参数;根据配置参数配置VxWorks操作系统,加载应用程序。本发明提供的参数化配置方法,通过根据计算机ID和预设参数配置文件...
- `ParameterInfo`类提供了关于方法、构造函数、属性或事件参数的详细信息,如名称、数据类型、参数方向等。 8. **反射在DLL中的应用**: - 加载DLL:`Assembly.LoadFrom(string filePath)`或`Assembly.Load(byte...
本文将详细介绍如何使用`TestName`来获取测试类和方法的名称,并讨论相关的编程细节。 首先,`TestName`是`TestWatcher`的一个子类,`TestWatcher`是一个观察者模式的实现,用于在测试方法开始前和结束后执行自定义...
在JavaScript中获取浏览器参数是一项常见的任务,这有助于开发者更好地了解用户环境,以便提供更好的兼容性和个性化体验。这篇博文“JS 获取浏览器参数”可能探讨了如何利用JavaScript来收集关于用户浏览器的信息,...
#### 获取串口名称的方法 要获取串口名称,我们可以使用`ManagementObjectSearcher`类,这是.NET Framework中的一部分,专门用于执行WMI查询。以下代码片段展示了如何实现这一功能: ```csharp using System; ...
在给定的代码示例中,作者定义了一个名为`request`的函数,该函数接受一个参数`paras`,用于指定想要获取的查询参数名称。函数的主要逻辑如下: 1. **获取完整的URL**:首先通过`location.href`获取当前页面的完整...
首先,需要通过调用getSystemService方法,并传入WIFI_SERVICE参数,来获取一个WifiManager实例。以下是具体的代码实现步骤: ```java WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE); ...
在Java编程中,获取系统参数是一项基本任务,用于了解运行Java程序的环境信息。Java提供了`java.lang.System`类的`getProperties()`方法来获取这些信息。这个方法返回一个`Properties`对象,该对象包含了关于Java...
在IT领域,获取设备参数是一项基础且至关重要的任务,它涉及到对硬件和软件系统的深入了解,以便于调试、优化、监控和管理。设备参数通常包括CPU信息、内存容量、硬盘细节、操作系统版本、网络配置以及各种硬件组件...