2017-12-27 3 views
0

Java環境で実行されているGroovyスクリプト内のすべてのメソッド呼び出しをインターセプトしようとしています。groovy内のすべてのメタクラスに対するすべてのメソッド呼び出しを傍受する

特に、すべてのメソッド呼び出しの戻り値の型をチェックしたい場合は、Xの場合はYに置き換えます。

私はあなたがMetaClass上でinvokeMethodを使用して傍受することができると知っていますが、私がコンパイルするスクリプトクラスに対してのみ行うことができます。スクリプトがクラスAのメソッドを呼び出すと、以前は手動でMetaClassをレジストリから手動でフェッチしてメタメソッドでオーバーライドすることなく、傍受できない新しいMetaClass[A]が作成されます。

私はGroovySystem.getMetaClassRegistry()を使用して、MetaClassが作成されたときにリスナーを追加しようとしましたが、そこにメタメソッドを追加することはありませんでした。

私はこれを自動化し、変換する必要のあるメソッドにアノテーションを追加する必要はなく、どのクラスのメソッドを変換するかを知る必要はありません。 Xを返すすべてのメソッドは、Yを返す必要があります。

すべてのメソッド呼び出しをグローバルに代行できますか?

代わりにMetaClassの作成を代行できますか?

自動AST変換を追加できますか?

答えて

0

これが可能です。 MetaClassCreationHandleの代わりにGroovySystem.getMetaClassRegistry().setMetaClassCreationHandleを呼び出す必要があります。

基本クラスMetaClassCreationHandleはパッケージプライベートなので、代わりにExpandoMetaClassCreationHandleから拡張する方が簡単かもしれません。しかし、すべてのクラスをExpandoMetaClassに基づいて作成する最も一般的な必要性のために、残念なことだと考えてください。だから、私がやったことは次のようなものでした:

GroovySystem.getMetaClassRegistry().setMetaClassCreationHandle(new ExpandoMetaClassCreationHandle() { 

    @Override 
    protected MetaClass createNormalMetaClass(Class theClass, MetaClassRegistry registry) { 

     final List<Method> propertyMethods = new ArrayList<>(); 
     for (Method method : theClass.getDeclaredMethods()) { 
      if (method.getReturnType() == TheMethodReturnTypeYouCareAbout.class) { 
       propertyMethods.add(method); 
      } 
     } 

     final MetaClass mc; 
     if (propertyMethods.isEmpty() == false) { 

      final ExpandoMetaClass expando = new ExpandoMetaClass(theClass, true, true); 
      for (Method mm : propertyMethods) { 
       final ClassInfo ci = ClassInfo.getClassInfo(mm.getDeclaringClass()); 
       expando.addMetaMethod(new MetaMethod() { 

        @Override 
        public int getModifiers() { 
         return mm.getModifiers(); 
        } 

        @Override 
        public String getName() { 
         return mm.getName(); 
        } 

        @Override 
        public Class getReturnType() { 
         return mm.getReturnType(); 
        } 

        @Override 
        public CachedClass getDeclaringClass() { 
         return ci.getCachedClass(); 
        } 

        @Override 
        protected Class[] getPT() { 
         return mm.getParameterTypes(); 
        } 

        @Override 
        public Object invoke(Object object, Object[] arguments) { 
         try { 
          final Object value = mm.invoke(object, arguments); 
          // Do whatever you need with the value. 
          return value; 
         } catch (Exception ex) { 
          throw new RuntimeException(ex); 
         } 
        } 
       }); 
      } 

      mc = expando; 
     } else if (GeneratedClosure.class.isAssignableFrom(theClass)) { 
      mc = new ClosureMetaClass(registry, theClass); 
     } else { 
      mc = new MetaClassImpl(registry, theClass); 
     } 

     return mc; 
    } 
}); 

これは、私たちがメタメソッドを追加する必要があるものに対してExpandoクラスを作成することを意味します。

関連する問題