本文向您展示Java反射机制的一个实例,该实例持简单EL的taglib,基本上实现了多级bean的属性的访问。
JSP的规范中,有个表达式语言(Expression Language, 简称EL),可以算是一个微型的语言,其中对request, page, session, application中预存的JavaBean对象的引用方式很是简单。最近正好需要写一个支持简单EL的taglib,所以就研究了下Java反射机制,目前基本上实现了多级bean的属性的访问,经测试,还是可以用的。如:
public static void main(String[] args){
UserBean bean = new UserBean();
bean.setName("John Abruzzi");
bean.setNick("Abruzzi");
bean.setAge(24);
AddressBean addr = new AddressBean();
addr.setZip("0086");
addr.setStreet("Bell Street #12");
bean.setAddress(addr);
System.out.println(BeanParser.doParse(bean, "bean.address.street"));
System.out.println(BeanParser.doParse(bean, "bean.address.zip"));
System.out.println(BeanParser.doParse(bean, "bean.name"));
System.out.println(BeanParser.doParse(bean, "bean.nick"));
System.out.println(BeanParser.doParse(bean, "bean.age"));
}
需要可以输出:
Bell Street #12
0086
John Abruzzi
Abruzzi
24
反射,即由一个抽象的对象(如Object),取出这个具体对象的属性或者方法(就EL中关于Bean的引用来说,这个定义已经够了)。在EL中,对一个Bean的某字段进行引用,只需 ${bean.field},当然,这个bean是已经被set到容器中的,这就是Java反射机制。
我们从容器中取出以bean为名字的Object,通过Java反射机制知道它的真实类型,然后通过field以javabean规范拼出方法名,进行调用,如果这个表达式是多级的,如${bean.field.field},其中第一个field本身就是一个bean对象,同样需要递归的进行解析。
大概原理就是这些了,看代码吧:
现有一个UserBean, 其中的一个字段Address本身又是一个AddressBean。
package elparser;
public class AddressBean {
private String street;
private String zip;
public String getZip() {
return zip;
}
public void setZip(String zip) {
this.zip = zip;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
然后是UserBean
ackage elparser;
public class UserBean {
private String name;
private String nick;
private AddressBean address;
private int age;
public int getAge(){
return this.age;
}
public void setAge(int age){
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNick() {
return nick;
}
public void setNick(String nick) {
this.nick = nick;
}
public AddressBean getAddress() {
return address;
}
public void setAddress(AddressBean address) {
this.address = address;
}
}
Bean都是很简单的,考虑到对基本类型的支持,所以在UserBean中加入一个int型的字段age
好了,看看怎么通过一个串和一个对象来取出其中的字段来:
kage elparser;
import java.lang.reflect.Method;
public class BeanParser {
private static String getMethodName(String property, String prefix){
String prop = Character.toUpperCase(property.charAt(0))+property.substring(1);
String methodName = prefix + prop;
return methodName;
}
private static Object parse(Object bean, String expr){
Class beanClass = bean.getClass();
Method method = null;
Object result = null;
try{
//这两步是关键,get方法不需要传入参数,所以只是new出两个空数组传入
method = beanClass.getMethod(getMethodName(expr, "get"), new Class[]{});
result = method.invoke(bean, new Object[]{});
}catch(Exception e){
System.out.println(e.getMessage());
}
return result;
}
public static Object doParse(Object bean, String expr){
String keys[] = expr.split("\\.");
Object obj = null;
for(int i = 1; i < keys.length;i++){
obj = parse(bean, keys[i]);
bean = obj;
}//递归parse
return obj;
}
public static void main(String[] args){
UserBean bean = new UserBean();
bean.setName("John Abruzzi");
bean.setNick("Abruzzi");
bean.setAge(24);
AddressBean addr = new AddressBean();
addr.setZip("0086");
addr.setStreet("Bell Street #12");
bean.setAddress(addr);
System.out.println(BeanParser.doParse(bean, "bean.address.street"));
System.out.println(BeanParser.doParse(bean, "bean.address.zip"));
System.out.println(BeanParser.doParse(bean, "bean.name"));
System.out.println(BeanParser.doParse(bean, "bean.nick"));
System.out.println(BeanParser.doParse(bean, "bean.age"));
}
}