PropertyDescriptor クラスのソースを見れば、このクラスがかなり複雑な構成を していることが分かります。PropertyDescriptor クラスは、 FeatureDescriptor クラスを継承しており、あるプロパティが「名前」や「値」を 持つという基本的な性質は、このFeatureDescriptor クラスによって担われている ことが分かります。
public class PropertyDescriptor extends FeatureDescriptor {
........
private Class propertyType; // Propertyの属するクラス
private Method readMethod; // Propertyを読み出すメソッド
private Method writeMethod; // Propertyを書き出すメソッド
private boolean bound; // Bound Propertyか?
private boolean constrained; // Constrained Propertyか?
private Class propertyEditorClass; // Propertyを編集するエディタのクラス
}
public class FeatureDescriptor {
........
private boolean expert; // Featureは "expert" か?
private boolean hidden; // Featureは "hidden" か?
private String shortDescription; // Featureの簡単な説明
private String name; // Featureの「名前」
private String displayName; // Featureのローカルな表示名
private java.util.Hashtable table; // Featureの「値」の格納場所
}
PropertyDescriptorクラスで拡張されたフィールドを見れば、BeansのPropertyは、 「名前」と「値」を持つだけでなく、どのようなクラスの値を持つのか、また、どの ようなメソッドによって読み書きされるのか、どのような種類(Bound、Constrained) のPropertyなのか、そして、それを編集するエディタのクラスの情報までも含んだ ものであることが分かります。
PropertyDescriptorのコンストラクタの型を見てみましょう。 いずれのコンストラクタも IntrospectionExceptionをthrowする可能性を持っている ことが分かります。もう一つ大事なことは、先にも触れましたが、Beansでは、 setter/getterと呼ばれる Propertyの値を読み書きするメソッドが、Propertyそのもの の一部を構成しているということです。
public PropertyDescriptor(String propertyName, Class beanClass)
throws IntrospectionException;
public PropertyDescriptor(String propertyName, Class beanClass,
String getterName, String setterName)
throws IntrospectionException ;
public PropertyDescriptor(String propertyName, Method getter, Method setter)
throws IntrospectionException ;
次のリストは、PropertyDescriptorの第一のコンストラクタのソースです。 このコンストラクタは、Propertyの名前とbeanクラスを与えると、そのクラスの PropertyDescriptorを生成します。この時、次のようなNaming Ruleが使われているの が分かります。今、fooというbeanクラスのbarという名前のPropertyの PropertyDescriptorを作るものとします。コンストラクタ new PropertyDescriptor("bar", foo); は、Introspectionを用いて、まず、クラス fooの中に、"setBar"という名前のメソッドがないかを調べ、あれば、それをsetter メソッドとします。setterの引数が boolean型だったら、今度は、"isBar"という名前の getterメソッドを探します。そうでなければ、"getBar"という名前のgetterを探します。いずれの検索でも、求めるメソッドが見つからなかったら、IntrospectionExceptionが 返されます。このリストで、"isBar"へのintrospectionは、exceptionがキャッチされて いるのは何故か考えて見て下さい。
public PropertyDescriptor(String propertyName, Class beanClass)
throws IntrospectionException {
setName(propertyName);
String base = capitalize(propertyName);
writeMethod = Introspector.findMethod(beanClass, "set" + base, 1);
// If it's a boolean property check for an "isFoo" first.
if (writeMethod.getParameterTypes()[0] == Boolean.TYPE) {
try {
readMethod = Introspector.findMethod(banClass, "is" + base, 0);
} catch (Exception ex) {
}
}
if (readMethod == null) {
readMethod = Introspector.findMethod(beanClass, "get" + base, 0);
}
findPropertyType();
}
PropertyDescriptorがどのように生成されるかという考察は、「Beansで Propertyを 定義するというのはどういうことなのか」という問いに、はっきりとした回答を与え ます。少し意外なことに、あるbeanクラスがPropertyの名前とPropertyTypeが等しい フィールドを持つことは、beanのPropertyにとって必要なことではありません。 肝心なことは、ある特定の型と名前をもつメソッドが存在することです。 bean クラス A で、プロパティ xyz を定義するということは、クラスAの定義の中に、 setXyzという名前のメソッド、あるいは、getXyz(または isXyz)という名前 のメソッドを定義しておくことなのです。 この点での詳しいアルゴリズムは、java.beans.Introspectorクラスの、 getTargetPropertyInfo()メソッドのソースをよく読んでみてください。