2008年11月28日星期五

JavaBean 之属性名称

问题:
在前端获取事件属性时,报错,找不到属性
目前的事件 SIMEventObject 中有这样的属性, sAddr,dAddr,它们的特的是第一个字母小写,第二个字母大写
但是在前端通过 ${event.sAddr}取值的时候,总是报找不到 sAddr 属性
这个问题以前也碰到过,但是没有往心里去,现在再次碰到,找了一下Java源码,才发现Java文档里其实有说明

原因:
1. 以前一直认为一个JavaBean,应该包括属性,setter,getter 方法,setter/getter 的命名规则则是将属性的第一个字母大写,前面加上 get/set ,但事实上不是这样,属性的名称跟 setter/getter 方法的名称无关,比如说,你可以这样写:

public class Bean{
private String anyword;

public void setProp(String anyword)
{ }
this.anyword = anyword;
}

public String getProp()
return anyword;
}
}

2. 对于 jstl 中的表达式 ${event.sAddr},实际的执行过程是这样:
a. 首选根据 event 的类型, 比如 SIMEventObject,得到其 BeanInfo
b. 在 BeanInfo 中 包含 event 的属性
c. 这个属性名称的来源是不是我们通常理解的 field, 而是根据 Bean 规范得到的(应该是根据 setter/getter 方法)
d. 得到属性名称时,它会将得到的属性字串的第一个字母去大写化,比如 由getDevAddr,得到 DevAddr,然后最后得到的是 devAddr;
e. 但是如果属性有多个字母,且第一个字母,第二个字母都大写的,则不做处理,比如 getSAddr,则直接返回 SAddr,也就是说,它认为 SAddr 是这个 Bean 的属性,而不是 sAddr

下面是部分过程代码:

BeanInfo mBeanInfo = Introspector.getBeanInfo (SIMEventObject.class);
PropertyDescriptor[] pds = mBeanInfo.getPropertyDescriptors();
Map propMap = new TreeMap();
Method readMethod = getPublicMethod (pd.getReadMethod ());
Method writeMethod = getPublicMethod (pd.getWriteMethod ());
BeanInfoProperty property = new BeanInfoProperty(readMethod,writeMethod,pd);

for(PropertyDescriptor pd : pds)
{
//问题在这里,就是 pd.getName(),对于第一个字母,第二个字母都是大写的,它不会做处理,即,SAddr/Saddr/SaDrr/saddr,返回 SAddr/saddr/saDrr/saddr 但对于其他情况,则将第一个字母变成小写返回,比如 saddr/SaDdr,则返回 saddr;但是当取值${event.sAddr}时,它会从 map 中获取属性,用如下方法: propMap.get("sAddr"),而实际上 propMap 中的key值是 SAddr,所以,如果我们将表达式换成 ${event.SAddr}
即可
propMap.put(pd.getName(),pd)
}


----------------------------------
将首字母变成小写调用是以下方法:
java.beans.Introspector
decapitalize
public static String decapitalize(String name)获得一个字符串并将它转换成普通 Java 可用名称大写形式的实用程序方法。这通常意味着将首字符从大写转换成小写,但在(不平常的)特殊情况下,当有多个字符且第一个和第二个字符都是大写字符时,不执行任何操作。
因此 "FooBah" 变成 "fooBah","X" 变成 "x",但 "URL" 仍然是 "URL"。

没有评论: