- PR -

J2SDKのバージョンアップによる動きの違い

1
投稿者投稿内容
Shrike
会議室デビュー日: 2007/12/25
投稿数: 2
投稿日時: 2007-12-25 14:00
業務アプリケーションのバージョンアップに伴い、J2SDKを1.4.2_05から1.4.2_16にあげたところ、org.apache.commons.beanutils.PropertyUtilsのメソッドcopyPropertiesで、実行時例外が発生しました。

詳しくソースを追ってデバックしたところ、JavaBeansのゲッターセッターがあいまいになる条件でjava.beans.PropertyDescriptor の動きが異なるようです。
サンプルコードでは、1.4.2_05で問題なく「OK.」となりますが、1.4.2_16では、例外を投げます。
SUNのbug databaseで調べても近くて異なる該当項目しか見当たらなかったので、報告しようか迷っています。
それとも、JavaBeansの仕様が厳密になったというアナウンス等があったのでしょうか?

(OS: Windows XP Pro SP2)

サンプルコード
▼[Value.java]
/**
* JavaBeans のオブジェクト
*
* setIdArray と getIdArray のオーバーロードされたメソッドがある。
*
* 上記のような条件を満たすメソッドがある場合に、
* java.beans.PropertyDescriptor クラスの
* getWriteMethod メソッド、getReadMethod メソッドは、
* J2SDK のバージョンにより異なる動きをみせる。
*
* @author Shrike
*
*/
public class Value {

private String[] idArray;

public void setIdArray(String[] idArray) {
this.idArray= idArray;
}

public String[] getIdArray() {
return idArray;
}

public Integer getIdArray(final int index) {
return null;
}

public void setIdArray(final int index, final Integer id) {
}
}

▼[PropertyDescriptorVerify.java]
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

/**
* PropertyDescriptorクラスの getWriteMethodメソッドを検証します。
*
* @author Shrike
*
*/
public class PropertyDescriptorVerify {

/**
* PropertyUtilsの動作を真似て、 getWriteMethodメソッドを検証します。
* @throws Exception
* @throws Exception
*/
public static void main(String[] args) throws Exception {

String name = "idArray";// Value オブジェクトのフィールド名前
Value value = new Value();// 対象となるJavaBeans オブジェクト

// value の BeanInfo を取得
BeanInfo beanInfo = null;
try {
beanInfo = Introspector.getBeanInfo(value.getClass());
} catch (IntrospectionException e) {

}

// PropertyDescriptor の配列を取得
PropertyDescriptor descriptors[] = beanInfo.getPropertyDescriptors();

// 指定したフィールド名のアクセッサを持つ PropertyDescriptorを取得。
PropertyDescriptor descriptor = null;
for (int i = 0; i < descriptors.length; i++) {
//動作確認
System.out.println("index: " + i);
System.out.println("name: " + descriptors[i].getName());
System.out.println("propertyType: " + descriptors[i].getPropertyType());
System.out.println("readMethod: " + descriptors[i].getReadMethod());
System.out.println("writeMethod: " + descriptors[i].getWriteMethod());
System.out.println("");

String accessorTarget = descriptors[i].getName();
if (name.equals(accessorTarget)) {
descriptor = descriptors[i];
break;
}
}
if (descriptor == null) {
// null の時は例外を発生(org.apache.commons.beanutils.PropertyUtils と同じ動き)
throw new NoSuchMethodException("Unknown property '" + name + "'");
}

Method writeMethod = descriptor.getWriteMethod();
if (writeMethod == null) {
// null の時は例外を発生(org.apache.commons.beanutils.PropertyUtils と同じ動き)
throw new NoSuchMethodException("Property '" + name + "' has no setter method");
}

System.out.println("OK.");
}
}


[ メッセージ編集済み 編集者: Shrike 編集日時 2007-12-27 00:53 ]
お犬様
ベテラン
会議室デビュー日: 2003/01/26
投稿数: 67
投稿日時: 2007-12-27 14:26
その部分に関しては明確に文書化されていない、いわゆる実装依存の範疇だと考えます。beans仕様の8. 自己検査には
引用:
8.10.7 クラス Introspector
クラスについての明示的な BeanInfo が見つからない場合は,低レベルの自己反映性を使用して,クラスのメソッドを調査し,標準設計パターンを適用して,特性アクセサ,イベントソース又は公開メソッドを識別する。その上で,クラスのスーパクラスの分析を続行し,そのスーパクラス(及びスーパクラスの連鎖までという可能性もある) からの情報に付加する

等と書かれていますが、今回のような曖昧なプロパティを含む場合に Introspector がどのように振舞うか、というような記述は一切ありません。また、私の見落としがなければ API仕様にも今回のような曖昧なプロパティを含む場合に、Introspector がどのように振舞うかは記述されていません。

今回のような曖昧なプロパティを含むbeanを扱うときは、明示的にBeanInfoを記述するのが一番確実だと思います。

また、1.4.2_05 と 1.4.2_16 で振る舞いが違う事に関しては1.4.2 のリリースノートをざっと見てみましたけど、5109847 のjava.beans.Introspector の退行 (プロパティの再順序付け)というのが一番怪しいかもしれません。
Shrike
会議室デビュー日: 2007/12/25
投稿数: 2
投稿日時: 2007-12-27 16:34
参考文献のご提示ありがとうございます。

リリースノートについては、私の方でもチェックしておりました。
「java.beans.Introspector の退行」は、bug database を見る限りでは、ステータスがclose, fixed になっているので、どうしたものかと思っていたところでもあります。

特殊な条件における修正漏れの可能性はありえそうですよね。
PropertyUtilsは、メモリリークをするとの噂も聞いたので、今回はこれを使わない方向で、対応することになりました。

新しく何か情報がわかりましたら、よろしくお願い致します。
こちらでも、何かわかった際には追記したいと思います。

ありがとうございました。
お犬様
ベテラン
会議室デビュー日: 2003/01/26
投稿数: 67
投稿日時: 2007-12-27 19:27
すいません説明不足だったようです。

件のPropertyDescriptorVerifyでreadMethodとwriteMethodがnullのPropertyDescriptorを返すのは実装者によって期待された動作なのではないかと考えます。

このreadMethod、writeMethodがnullのPropertyDescriptorはIndexedPropertyDescriptor のインスタンスで、getIndexedReadMethod()やgetIndexedWriteMethod()を使えば Value#getIdArray(int)やValue#setIdArray(int, Integer)が得られるはずです。そして、この動作は1.3.1_20と同じ動作です。また、1.2.2_017で同じ事をするとインデクス付きプロパティとインデクス無しのプロパティの要素型が代入互換でないにも関わらず
引用:
name: idArray
propertyType: class [Ljava.lang.String;
readMethod: public java.lang.String[] Value.getIdArray()
writeMethod: public void Value.setIdArray(java.lang.String[])
indexedPropertyType: class java.lang.Integer
indexedReadMethod: public java.lang.Integer Value.getIdArray(int)
indexedWriteMethod: public void Value.setIdArray(int,java.lang.Integer)

となるようなIndexedPropertyDescriptorを返してきます。この1.2.2_017の振る舞いは変ですから、1.3.1_20で一旦は修正されたのではないでしょうか。そして 1.4.2 の初期にregressionを起こして(再び1.2.2_017のような振る舞いをして)いたため 5109847が修正された時に、一緒に修正されたのではないかと考えています。
1

スキルアップ/キャリアアップ(JOB@IT)