java内省(同反射)获取属性的getter\setter方法等

内省是 Java 语言对 Bean 类属性、事件的一种处理方法(也就是说给定一个javabean对象,我们就可以得到/调用它的所有的get/set方法)。例如类 A 中有属性 name, 那我们可以通过 getName,setName 来得到其值或者设置新的值。通过 getName/setName 来访问 name 属性,这就是默认的规则。 Java 中提供了一套 API 用来访问某个属性的 getter/setter 方法,通过这些 API 可以使你不需要了解这个规则,这些 API 存放于包 java.beans 中。

 

    一般的做法是通过类 Introspector 来获取某个对象的 BeanInfo 信息,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后我们就可以通过反射机制来调用这些方法。

另外:我们可以通过propertyDescriptor的构造函数获取一个propertyDescriptor。如下图

PropertyDescriptor

public PropertyDescriptor(String propertyName,
                          Class<?> beanClass)
                   throws IntrospectionException
Parameters:
propertyName - The programmatic name of the property.
beanClass - The Class object for the target bean. For example sun.beans.OurButton.class.
Throws:
IntrospectionException - if an exception occurs during introspection.

 

下面我们来看一个例子,这个例子把某个对象的所有属性名称和值都打印出来:

//定义一个javabean
public class PersonBean {
   public String name;
   public String[] childname;
   public String[] getChildname() {
      return childname;
   }
   public void setChildname(String[] childname) {
      this.childname = childname;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
}
 
//定义一个测试类,来进行一下set和get方法的调用举例
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
public class TestIntrospector {
   public static void main(String[] args) throws IllegalArgumentException,
                           IllegalAccessException, SecurityException, NoSuchMethodException,
                           InvocationTargetException, IntrospectionException {
  //演示一下get方法的调用
      //初始化一个javabean对象
      PersonBean pb=new PersonBean();
      pb.setName("kangjian");
      String[] childs=new String[]{"kk","jj","nn"};
      pb.setChildname(childs);
      //将该javabean中的属性放入到BeanInfo中。第二个参数为截止参数,表示截止到此类之前,
       不包括此类。如果不设置的话,那么将会得到本类以及其所有父类的info。
      BeanInfo bi=Introspector.getBeanInfo(pb.getClass(), Object.class);
      //将每个属性的信息封装到一个PropertyDescriptor形成一个数组
        其中包括属性名字,读写方法,属性的类型等等
      PropertyDescriptor[] pd=bi.getPropertyDescriptors();
      //演示如何get
      for (int i = 0; i < pd.length; i++) {
         if(pd[i].getPropertyType().isArray())  //getPropertyType得到属性类型。
         {
            //getReadMethod()得到此属性的get方法----Method对象,然后用invoke调用这个方法
            String[] result=(String[]) pd[i].getReadMethod().invoke(pb, null);
            System.out.println(pd[i].getName()+":");//getName得到属性名字
            for (int j = 0; j < result.length; j++) {
               System.out.println(result[j]);
            }
         }
         else
         {
            System.out.println(pd[i].getName()+":"+pd[i].getReadMethod().invoke(pb, null));
         }
      }
  //演示一下set方法的调用
      //初始化一个尚未set的javabean
      PersonBean pb0=new PersonBean();
      //模拟一个数据(数据名字和javabean的属性名一致)
      String name="luonan";
      String[] childname=new String[]{"luo","nan"};
 
      BeanInfo bi0=Introspector.getBeanInfo(pb0.getClass(), Object.class);
      PropertyDescriptor[] pd0=bi0.getPropertyDescriptors();
 
      for (int i = 0; i < pd0.length; i++) {
         if(pd0[i].getPropertyType().isArray())
         {
            if(pd0[i].getName().equals("childname"));
            {
               if(pd0[i].getPropertyType().getComponentType().equals(String.class))
               {//getComponentType()可以得到数组类型的元素类型
                  //getWriteMethod()得到此属性的set方法---Method对象,然后用invoke调用这个方法
                  pd0[i].getWriteMethod().invoke(pb0,new Object[]{childname});
               }
            }
         }
         else
         {
            if(pd0[i].getName().equals("name"));
            {
               pd0[i].getWriteMethod().invoke(pb0,name);
            }
         }
      }
 
      System.out.println(pb0.getName());
      String[] array=pb0.getChildname();
      for (int i = 0; i < array.length; i++) {
         System.out.println(array[i]);
      }
   }
}
 
 
三、关于内省的思考
    struts2的action(还有struts1的formbean)就是这么实现的。
    前台的form标签具有一些属性(在配置文件中知道这个form提交到那个action,而这个action有和这个form相对应的属性及其 get/set),提交以后,由struts的servlet拦下来转发给某个具体的action.而在转发给action之前struts通过内省的方式将form中的值set到了action中去。
    其实只要有个set**或者get**,内省就会理解为存在这样的**属性,这样可以方便我们把 Bean 类通过一个接口来定义而不用去关心具体实现,不用去关心 Bean 中数据的存储。比如我们可以把所有的 getter/setter 方法放到接口里定义,但是真正数据的存取则是在具体类中去实现,这样可提高系统的扩展性。
四、总结
    将 Java 的反射以及内省应用到程序设计中去可以大大的提供程序的智能化和可扩展性。有很多项目都是采取这两种技术来实现其核心功能,例如我们前面提到的 Struts ,还有用于处理 XML 文件的 Digester 项目,其实应该说几乎所有的项目都或多或少的采用这两种技术。在实际应用过程中二者要相互结合方能发挥真正的智能化以及高度可扩展性。
五、高级代码

package com.selfCommunion;

import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;

/**
*
* @author yangkun
*
* 该类的功能和JSP的自省机制相同 大量模仿(改版)了tomcat的源码
* 可以不用通过request.getParamement("formElementName")来获得值
* 直接通过本类的introspect就可以实现实体类的封装
*
* 示例: SelfCommunion box=new SelfCommunion(); Student bean=new Student();
* box.introspect(bean,request);
*
* <form name="f1" id="f1" action="servlet/Login" method="post"> <table
* border="0">
* <tr>
* <td>Login:</td>
* <td><input type="text" name="name" id="name"></td>
* </tr>
* <tr>
* <td>Password:</td>
* <td><input type="password" name="pwd" id="pwd"></td>
* </tr>
* <tr>
* <td colspan="2" align="center"><input type="submit"></td>
* </tr>
* </table> </form>
*
*
* public class Student implements Serializable { public Student() { super(); }
* String name; String pwd; public String getName() { return name; } public void
* setName(String name) { this.name = name; } public String getPwd() { return
* pwd; } public void setPwd(String pwd) { this.pwd = pwd; } }
*
* 这样就可以把form表单中的数据封装的实体类中(必须表单元素的名字和实体类中的属性名称一样)
*
*/
public class SelfCommunion {

public SelfCommunion() {
   super();
}

public static void introspect(Object bean, ServletRequest request)
    throws ServletException {
   Enumeration e = request.getParameterNames();
   while (e.hasMoreElements()) {
    String name = (String) e.nextElement();
    String value = request.getParameter(name);
    introspecthelper(bean, name, value, request, name, true);
   }
}

public static void introspecthelper(Object bean, String prop, String value,
    ServletRequest request, String param, boolean ignoreMethodNF)
    throws ServletException {
   // 获得系统安全接口。 如果已经为当前应用程序建立了安全管理器,则返回此安全管理器;否则,返回 null。
   if (System.getSecurityManager() != null) {
    try {
     PrivilegedIntrospectHelper dp = new PrivilegedIntrospectHelper(
       bean, prop, value, request, param, ignoreMethodNF);
     // 启用对PrivilegedIntrospectHelper的特权,在执行run方法,在run方法中执行internalIntrospecthelper
     AccessController.doPrivileged(dp);
    } catch (PrivilegedActionException pe) {
     Exception e = pe.getException();
     throw (ServletException) e;
    }
   } else {
    internalIntrospecthelper(bean, prop, value, request, param,
      ignoreMethodNF);
   }
}

private static void internalIntrospecthelper(Object bean, String prop,
    String value, ServletRequest request, String param,
    boolean ignoreMethodNF) throws ServletException {
   Method method = null;
   Class type = null;
   Class propertyEditorClass = null;
   try {
    // 在 Java Bean 上进行内省,了解其所有属性、公开的方法和事件。
    java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean
      .getClass());
    if (info != null) {
     // 描述受此 bean 支持的可编辑属性的 PropertyDescriptor
     // 数组。如果该信息应该通过自动分析获得,则可能返回 null。
     java.beans.PropertyDescriptor pd[] = info
       .getPropertyDescriptors();
     for (int i = 0; i < pd.length; i++) {
      // 如果i的属性名称和prop一样
      if (pd[i].getName().equals(prop)) {
       // 获得应该用于写入属性值的方法。
       method = pd[i].getWriteMethod();
       // 获得属性的 Class 对象。
       type = pd[i].getPropertyType();
       // 获得已为此属性注册的任何显式 PropertyEditor Class。
       propertyEditorClass = pd[i].getPropertyEditorClass();
       break;
      }
     }
    }
    // 如果写入属性值的方法不为空
    if (method != null) {
     // 如果属性类型是数组
     if (type.isArray()) {
      if (request == null) {
       throw new ServletException(
         "jsp.error.beans.setproperty.noindexset");
      }
      Class t = type.getComponentType();
      String[] values = request.getParameterValues(param);
      // XXX Please check.
      if (values == null)
       return;
      if (t.equals(String.class)) {
       method.invoke(bean, new Object[] { values });
      } else {
       createTypedArray(prop, bean, method, values, t,
         propertyEditorClass);
      }
     } else {// 如果属性类型不是数组
      // 如果值=null,获着值=“”
      if (value == null || (param != null && value.equals("")))
       return;

      Object oval = convert(prop, value, type,
        propertyEditorClass);
      if (oval != null)
       method.invoke(bean, new Object[] { oval });
     }
    }
   } catch (Exception ex) {
    throw new ServletException(ex);
   }
   if (!ignoreMethodNF && (method == null)) {
    if (type == null) {
     throw new ServletException("jsp.error.beans.noproperty" + "_"
       + prop + "_" + bean.getClass().getName());
    } else {
     throw new ServletException(
       "jsp.error.beans.nomethod.setproperty" + "_" + prop
         + "_" + type.getName() + "_"
         + bean.getClass().getName());
    }
   }
}

public static Object getValueFromBeanInfoPropertyEditor(Class attrClass,
    String attrName, String attrValue, Class propertyEditorClass)
    throws ServletException {
   try {
    PropertyEditor pe = (PropertyEditor) propertyEditorClass
      .newInstance();
    pe.setAsText(attrValue);
    // 获得属性值。将基本类型(比如 "int")包装为相应的对象类型,比如 "java.lang.Integer"。
    return pe.getValue();
   } catch (Exception ex) {
    throw new ServletException("jsp.error.beans.property.conversion"
      + "_" + attrValue + "_" + attrClass.getName() + "_"
      + attrName + "_" + ex.getMessage());
   }
}

// 给Bean的属性赋值
public static Object getValueFromPropertyEditorManager(Class attrClass,
    String attrName, String attrValue) throws ServletException {
   try {
    PropertyEditor propEditor = PropertyEditorManager
      .findEditor(attrClass);
    if (propEditor != null) {
     // 赋值
     propEditor.setAsText(attrValue);
     return propEditor.getValue();
    } else {
     throw new IllegalArgumentException(
       "jsp.error.beans.propertyeditor.notregistered");
    }
   } catch (IllegalArgumentException ex) {
    throw new ServletException("jsp.error.beans.property.conversion"
      + "_" + attrValue + "_" + attrClass.getName() + "_"
      + attrName + "_" + ex.getMessage());
   }
}//

protected static class PrivilegedIntrospectHelper implements
    PrivilegedExceptionAction {

   private Object bean;

   private String prop;

   private String value;

   private ServletRequest request;

   private String param;

   private boolean ignoreMethodNF;

   PrivilegedIntrospectHelper(Object bean, String prop, String value,
     ServletRequest request, String param, boolean ignoreMethodNF) {
    this.bean = bean;
    this.prop = prop;
    this.value = value;
    this.request = request;
    this.param = param;
    this.ignoreMethodNF = ignoreMethodNF;
   }

   public Object run() throws ServletException {
    internalIntrospecthelper(bean, prop, value, request, param,
      ignoreMethodNF);
    return null;
   }
}

public static Object convert(String propertyName, String s, Class t,
    Class propertyEditorClass) throws ServletException {
   try {
    if (s == null) {
     if (t.equals(Boolean.class) || t.equals(Boolean.TYPE))
      s = "false";
     else
      return null;
    }
    if (propertyEditorClass != null) {
     return getValueFromBeanInfoPropertyEditor(t, propertyName, s,
       propertyEditorClass);
    } else if (t.equals(Boolean.class) || t.equals(Boolean.TYPE)) {
     if (s.equalsIgnoreCase("on") || s.equalsIgnoreCase("true"))
      s = "true";
     else
      s = "false";

     return new Boolean(s);
    } else if (t.equals(Byte.class) || t.equals(Byte.TYPE)) {
     return new Byte(s);
    } else if (t.equals(Character.class) || t.equals(Character.TYPE)) {
     return s.length() > 0 ? new Character(s.charAt(0)) : null;
    } else if (t.equals(Short.class) || t.equals(Short.TYPE)) {
     return new Short(s);
    } else if (t.equals(Integer.class) || t.equals(Integer.TYPE)) {
     return new Integer(s);
    } else if (t.equals(Float.class) || t.equals(Float.TYPE)) {
     return new Float(s);
    } else if (t.equals(Long.class) || t.equals(Long.TYPE)) {
     return new Long(s);
    } else if (t.equals(Double.class) || t.equals(Double.TYPE)) {
     return new Double(s);
    } else if (t.equals(String.class)) {
     return s;
    } else if (t.equals(java.io.File.class)) {
     return new java.io.File(s);
    } else if (t.getName().equals("java.lang.Object")) {
     return new Object[] { s };
    } else {
     return getValueFromPropertyEditorManager(t, propertyName, s);
    }
   } catch (Exception ex) {
    throw new ServletException(ex);
   }
}

public static void createTypedArray(String propertyName, Object bean,
    Method method, String[] values, Class t, Class propertyEditorClass)
    throws ServletException {

   try {
    if (propertyEditorClass != null) {
     Object[] tmpval = new Integer[values.length];
     for (int i = 0; i < values.length; i++) {
      tmpval[i] = getValueFromBeanInfoPropertyEditor(t,
        propertyName, values[i], propertyEditorClass);
     }
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(Integer.class)) {
     Integer[] tmpval = new Integer[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = new Integer(values[i]);
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(Byte.class)) {
     Byte[] tmpval = new Byte[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = new Byte(values[i]);
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(Boolean.class)) {
     Boolean[] tmpval = new Boolean[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = new Boolean(values[i]);
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(Short.class)) {
     Short[] tmpval = new Short[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = new Short(values[i]);
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(Long.class)) {
     Long[] tmpval = new Long[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = new Long(values[i]);
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(Double.class)) {
     Double[] tmpval = new Double[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = new Double(values[i]);
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(Float.class)) {
     Float[] tmpval = new Float[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = new Float(values[i]);
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(Character.class)) {
     Character[] tmpval = new Character[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = new Character(values[i].charAt(0));
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(int.class)) {
     int[] tmpval = new int[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = Integer.parseInt(values[i]);
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(byte.class)) {
     byte[] tmpval = new byte[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = Byte.parseByte(values[i]);
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(boolean.class)) {
     boolean[] tmpval = new boolean[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = (Boolean.valueOf(values[i])).booleanValue();
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(short.class)) {
     short[] tmpval = new short[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = Short.parseShort(values[i]);
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(long.class)) {
     long[] tmpval = new long[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = Long.parseLong(values[i]);
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(double.class)) {
     double[] tmpval = new double[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = Double.valueOf(values[i]).doubleValue();
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(float.class)) {
     float[] tmpval = new float[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = Float.valueOf(values[i]).floatValue();
     method.invoke(bean, new Object[] { tmpval });
    } else if (t.equals(char.class)) {
     char[] tmpval = new char[values.length];
     for (int i = 0; i < values.length; i++)
      tmpval[i] = values[i].charAt(0);
     method.invoke(bean, new Object[] { tmpval });
    } else {
     Object[] tmpval = new Integer[values.length];
     for (int i = 0; i < values.length; i++) {
      tmpval[i] = getValueFromPropertyEditorManager(t,
        propertyName, values[i]);
     }
     method.invoke(bean, new Object[] { tmpval });
    }
   } catch (Exception ex) {
    throw new ServletException("error in invoking method", ex);
   }
}

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值