2013-04-30 23 views
9

これは奇妙なエラーのようですが、Enum.valueOf(type, name)はOracle JDK 7 SEでは不安定に見えます。Enum.valueOf .values()が壊れてしまうJDK 7 SEのバグ

正確に同じ名前の文字列(これを確認した)で、valueOf()を呼び出すと、メッセージNo enum constant ...IllegalArgumentExceptionがスローされることがあります。

私のチームはEclipseデバッガーでこれを実行しました。次のJDK実装のvalueOfの値はenumConstantDirectory()です。すなわち、values()の列挙型のリストは時々値が欠落しているようです。列挙型自体で定義されたすべての値の全体ではありません。

JVMの起動時にすべての可能な列挙値に対してEnum.valueOf(enumclass.class, "XXX")を呼び出すことで、このバグを回避できます。これを行うと、values()には常にフルセットが含まれているようです。

ただし、このタイプの初期化を行わないと、Enum.valueOf()IllegalArgumentExceptionを投げることがあります。

コンテキスト:XStream 1.4.4を使用してenumを変換するPOJOオブジェクトを変換するときにこの問題が発生していますが、この問題は本質的にXStreamではないようです。

誰でもこの種のエラーが発生しましたか?あなたがいるなら、それについて聞いてみたいと思う。 それは私の心を揺さぶる。これはOracle JDK/JVM実装のバグですか?

public static <T extends Enum<T>> T valueOf(Class<T> enumType, 
              String name) { 
    T result = enumType.enumConstantDirectory().get(name); 
    if (result != null) 
     return result; 
    if (name == null) 
     throw new NullPointerException("Name is null"); 
    throw new IllegalArgumentException(
     "No enum constant " + enumType.getCanonicalName() + "." + name); 
} 

その他の関連する詳細:

私たちは、起動時に我々のコード内のすべての列挙型をスキャンするorg.reflectionsライブラリを使用しています。スキャン中に列挙型を取得し、列挙型に関連付けられたClassオブジェクトに対してclazz.getEnumConstants()を呼び出します。これは関連する詳細かもしれません。

実装では、java.lang.Class.getEnumConstants()の実装では、クラス内で同じenumConstants共有オブジェクトを共有しているようです。ここに実装上の問題があるのだろうかと思います。

私たちの列挙には、編集

public enum ScreeningRuleType 
{ 
    INSERT, 
    CONFIRMATION, 
    AMOUNT, 
    EXISTENCE, 
    BAN, 
    SELECTION, 
    CUSTOM; 

    private long id; 
    private String descr; 

    ScreeningRuleType() 
    { 
    id = this.ordinal(); 
    descr= this.toString().replace("_", " "); 
    } 
} 

など、静的な初期化の非常に単純ではありません。これを試して 、私は別の症状を見つけることです。 System.outの初期化を使用した後で、IllegalArgumentExceptionをスローするのではなく、Enum.valueOfから返された値がランダムなようです。

これはEclipseデバッガで表示されている内容を示しています。これは、文字列 "EXISTENCE"と "EXISTENCE" .intern()でvalueOf()を呼び出していることを明確に示し、代わりにAMOUNT()が返されていることを明確に示しています。

Debugger expression

+0

間欠障害が発生することがあります。何か目立つパターンがありますか?どのくらいの頻度で失敗するのですか? – Zyerah

+0

送信している文字列に埋め込みヌルが含まれている可能性はありますか?そのような場合は、正しい定数を選択していない可能性があります。 –

+0

いくつかのコードパスでのみ失敗しますが、そのコードパスで再現できます。単体テストの開始時にSystem.out.println(Enum.valueOf(type、 "xxx"))にコード行を追加するだけで、エラーはなくなります。 – zzhu8192

答えて

4

実際に問題が見つかりました。それは顔+掌の瞬間です。列挙型を含むクラスの深刻な(非シャロー)コピーを試みることによって、リフレクションAPIを介して列挙型を破損しました。これは、シングルトン列挙自体のすべてのインスタンス変数を消去する効果がありました。すべての助けと提案に感謝します。

6

私は似たような出くわしたところ、私は忘れて - 私はそれが前のJava 7だったとJava 4/5日で戻ってきている可能性があることが疑われます。

enumの付随する構造の構築は、初めてenumのうちの1つがアクセスされたときにのみトリガされるという問題があります。残念なことに、これらの構造に依存するメソッドの1つを呼び出す場合、またはEnumSet.allOfたとえばの前にのいずれかにアクセスすると、それは一般的に致命的に失敗します。

悲しいことに私はコードをリファクタリングしていました。これが起こらないように、私はもうサンプルを手にすることができません。私は問題を再現し、あなたに連絡しようとします。

私はここにいます - Why the Java enum constants initialization is not complete?デモンストレーションによる別の問題の発生。

+0

ええ、静的な初期化子内の循環依存性のように聞こえます。 /それはデッドロックしない幸運の種類。まあ、特定の条件の下で時にはうまくいくかもしれません。 –

+0

@OldCurmudgeon、それは非常に素晴らしい情報です!私はそれがあなたがそれに遭遇するまで、あなたが認識も認識もしていないものの一つだと思います。 –

+0

これは、静的な初期化順序の問題のように見えますが、これは私たちが行っているのと全く同じ例ではありません。私たちのケースでは、あなたの例によるMyEnum.values()は値の1つを欠いていて、非公式の値2を持っていません。 – zzhu8192

関連する問題