内省是 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.
下面我们来看一个例子,这个例子把某个对象的所有属性名称和值都打印出来:
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);
}
}
}