最近在JDK1.8环境下 使用Introspector获取bean属性名以及类型信息等(PropertyDescriptor),用于将Map内的元素赋值给bean属性时,遇到有特殊属性无论如何也无法赋值的情况。故查看了jdk该方法的实现细节,现将代码标记如下:
获取bean属性信息代码:PropertyDescriptor[] props = Introspector.getBeanInfo(desBeanClazz).getPropertyDescriptors();
执行流程大致为:Introspector->getBeanInfo->new GenericBeanInfo->getTargetPropertyInfo->new PropertyDescriptor->setName(Introspector.decapitalize(base))
我们看到属性名的关键在于:setName(Introspector.decapitalize(base))
于是查看Introspector.decapitalize(String name)方法的具体实现:
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
该方法在第二个if判断时,判断如果name第一和第二个字母为大写,则直接返回name,否则将name首字母转为小写返回name。
我们再来查看decapitalize方法的name来源:
截取getTargetPropertyInfo()关键代码
String name = method.getName();
if (name.startsWith(GET_PREFIX)) {
// Simple getter
pd = new PropertyDescriptor(this.beanClass, name.substring(3), method, null);
}
可以看到属性名是根据bean的get方法名去掉前三位之后转换而来。如果我们的属性名是 qTitle,那么对应的get方法名为getQTitle,decapitalize方法获取到的属性名将会是QTitle,故无法成功赋值。
我们查看decapitalize方法的注释:
/** * Utility method to take a string and convert it to normal Java variable * name capitalization. This normally means converting the first * character from upper case to lower case, but in the (unusual) special * case when there is more than one character and both the first and * second characters are upper case, we leave it alone. * <p> * Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays * as "URL". * * @param name The string to be decapitalized. * @return The decapitalized version of the string. */
大意是说该方法会将字符串转为java变量名的格式,通常情况下的做法是将首字母小写,但是当首字母和第二个字母都是大写时,则不做此转换。
由此,我们可以得知jdk对于java属性名命名时,并不推荐qTitle这样的命名格式。望后来者若要命名第一个字母小写第二个字母大写的属性名时,一定要慎重。