2011-07-28 2 views
2

の期間の後に私たちは、nullの場合も、このGroovyはlist.find呼び出しでNPEを与えるだけの時間

// semi-pseudo code 
def result = someList.find { condition == true } 

someListのようなコードに何かの塊を持っているが、それは正常に動作グルーヴィーnull.find{…}ようにokです。)

このコード行は、grailsコントローラのアクションで実行されており、本番環境ではサーバーにデプロイされています。ある期間(時には時には時間がかかることもある)の後、上記のコード行はNullPointerExceptionをスローし始めます。そして、NPEを投げ始めると常にNPEを投げます。

someListがnullの場合でも、デバッグを行うと、うまく動作することがわかりました。(最初のNPEがランダムになるまで)...デバッグでも、エラーが示された詳細スタックトレースをGroovy MetaClassRegistryImpl.javaライン214

stack trace

私は、任意の既知のGroovyのバグがあるかどうかを確認するために私は考えることができるすべての組み合わせをグーグルが、値の何も見つからなかっました。

A JMeterのスクリプトは、この問題は半繰り返し可能になり、サイトの一連の相互作用を介して実行するように設定した(このようなGroovy 1.7.8、Grailsの1.3.7を使用しています)。スクリプトは50-100シリーズを反復してエラーが表示されます。エラーが表示されると、アプリケーションがサーバー(Glassfish)に再デプロイされるまで常にエラーになります。

それは次のようになりますグルーヴィーコードをトレース:

//AbstractCallSite.java 
public Object call(Object receiver, Object arg1) throws Throwable { 
    return call(receiver, ArrayUtil.createArray(arg1)); 
} 

//PerInstancePojoMetaClassSite.java 
public Object call(Object receiver, Object[] args) throws Throwable { 
    if (info.hasPerInstanceMetaClasses()) { 
     try { 
      return InvokerHelper.getMetaClass(receiver).invokeMethod(receiver, name, args); 
     } catch (GroovyRuntimeException gre) { 
      throw ScriptBytecodeAdapter.unwrap(gre); 
     } 
    } else { 
     return CallSiteArray.defaultCall(this, receiver, args); 
    } 
} 


//InvokerHelper.java 
public static MetaClass getMetaClass(Object object) { 
    if (object instanceof GroovyObject) 
     return ((GroovyObject) object).getMetaClass(); 
    else 
     return ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(object); 
} 

//MetaClassRegistryImpl.java 
public MetaClass getMetaClass(Object obj) { 
    return ClassInfo.getClassInfo(obj.getClass()).getMetaClass(obj); 
} 

だから、NPEがobj.getClass()上で表示されます - そのような場合、私はsomeListがnullのとき、それは今までどのように動作するか少しバッフル付きです(しかしそれは別の話題です)。

FWIW、私たちはではありませんsomeListに私たちの任意のクラスまたはインスタンスレベルのメタクラスコードを行っています。

Groovyにバグがありますか、またはGroovyコードの(ランダムな)NPEが深刻な原因になる可能性がありますか?

UPDATE-

観察はsomeList 'はJavaのnull' の代わりに 'グルービーヌル'(NullObject)に設定されていることです。オブジェクトは...コントローラのアクションのフローを経由してマップ(フローコンテキスト)から来ている

class SomeController { 

    def someActionFlow = { 
     action { 

      def someList = flow.someList 

     } 
    } 
} 

問題の場合は、flow.someListが設定されていないとき、それは常にnull(グルーヴィーヌル)であるべきです。それは上記のコードは、反復の数が不明のため正常に動作して、代わりに「グルーヴィーヌル」の「Javaのヌル」を返す開始しflow.get('someList')

をやってと同じであるので、flowはただのマップです。

+0

をコミットする特定の状況下でのNPEを回避するために、受信機はnullチェックを追加するにはFWIW、 'DEF = someListを引き起こします?。 find {condition == true} 'は問題を解決します。したがって、安全なナビゲーション演算子が解決策であるように見えますが、GroovyのNullObjectに関するこの問題のためにリファクタリングする必要のある、すでに生産中のコードがたくさんあります。 –

+0

関連:http://stackoverflow.com/questions/5472795/groovy-why-i-dont-get-a-nullpointerexception-in-this-case –

答えて

3

私はそれがどのようにsomeListが作成されたかに依存していると推測する危険性があります。それはそれは

def someList = null 

としてGroovyで作成されます場合は、Groovyの変数にNullObjectを割り当て、です。ただし、値が他のJavaコンポーネントから実際のJavaのnullとして返された場合は、NPEがスローされます。さらに、Groovy/Java/JVMには、callsiteキャッシングがNPEを常に返すような最適化が行われることがあります。

もう一度、これは単なる野生の推測です。固定

+0

私もこのプロジェクトに携わっており、私たちが見つけたのはまさにそれでした。 'println someList.getClass()'は、NPEがスローされるまで 'NullObject'を返しました。その場合、NullがJavaの' null'です。これはわかっていましたが、このオブジェクトが 'NullObject'から' null'に変換されているかどうかわかりません。 –

+0

それでは、どうやって "Java null"と "Groovy null"になるのでしょうか? –

+0

groovy/grailsが、フローコンテキストマップからNullObjectを返すことから、同じ呼び出しに対して実際のJavaのnullを返すことに切り替えることで、根本的な問題が何であるかわからなくても、これを答えとしてチェックしています。 –

1

:同様にGROOVY-5248(ヌルチェックを欠落している呼び出しサイトのキャッシュ)に、

はまた641c6a8d4b6b3046f4d8a1a2ac5f08f1f2769f0f

関連する問題