2017-04-27 10 views
0

Groovyスクリプトを実行する拡張機能を追加するJavaアプリケーションがあります。これまでのところ、構文解析、コンパイル、実行は問題ありません!複数のデリゲートの処理

簡素化の理由から、groovyの構文はできるだけシンプルにしたい(例:OOスキルは必要ありません)。さらに、Groovyスクリプトは、Javaクラスによって初期化されたライブラリ関数にアクセスできるものとする。これは、@Delegateが出場する部分です!

public interface GroovyService { } 

MyService.java

public class MyService implements GroovyService { 

    public static final MyService INSTANCE = new MyService(); 

    private MyService() { /* ... */ } 

    public void method1() { /* ... */ } 

    public void method2() { /* ... */ } 

} 

GroovyService.java

現在、私は私のために完全に満足していない2つの異なる解決策を思い付きましたソリューション#1 - 委任された各メソッドについて、 Dショートカット

ServicesFacade.java

public class ServicesFacade { 

    public static final ServicesFacade INSTANCE = new ServicesFacade(); 

    @Delegate MyService myService; 
    // Further @Delegate of services ... 

    private ServicesFacade() { 
    myService = MyService.INSTANCE; 
    } 

} 

GroovyScript.groovy

def method1 = myService.&method1 
def method2 = myService.&method2 

if (method1()) { 
    method2() 
} 

方法ショートカットとコード部はかっこいいファイルから読み取られた文字列の結果の前に付加することができますコンテンツ。ショートカットがなければ、それは私の期待を満たすだろうが、すべてのショートカットを追跡する必要がないソリューションを探している。

溶液#2 - サービスタイプのリストとメソッドのワイルドカードへのアクセスを使用し

ServicesFacade.java

public class ServicesFacade { 

    public static final ServicesFacade INSTANCE = new ServicesFacade(); 

    @Delegate private final List<GroovyService> services = new ArrayList<>(); 

    private ServicesFacade() { 
    this.services.add(MyService.INSTANCE); 
    } 

    public void addService(GroovyService service) { 
    this.services.add(service); 
    } 

} 

GroovyScript.groovy

if (services*.method1()) { 
    services*.method2() 
} 

このソリューションの利点は次のとおりです。私は任意のサービス(サービス*)に固定されたメンバー名を使用できますが、構文にはあまり感心しません。次のように

グルーヴィーなスクリプトが使用されています。

CompilerConfiguration compilerConfiguration = new CompilerConfiguration(); 
compilerConfiguration.setScriptBaseClass(DelegatingScript.class.getName()); 
GroovyShell groovyShell = new GroovyShell(compilerConfiguration); 
DelegatingScript script = (DelegatingScript) groovyShell.parse(fileContent); 

if (script != null) { 
    script.setDelegate(ServicesFacade.INSTANCE); 
    scripts.add(script); 
} 
/* ... */ 
scripts.forEach(s -> { 
    s.run(); 
}); 

は委譲メソッドの直接メソッド呼び出しを達成するための良い方法はありますか?

答えて

0

私は、DelegatingScriptに類似した類似のScriptクラスを書いた良い解決策を考え出しました。これは次のようになります。このクラスの代わりに、DelegatingScriptを使用して

import groovy.lang.Binding; 
import groovy.lang.MetaClass; 
import groovy.lang.MissingMethodException; 

import org.codehaus.groovy.runtime.InvokerHelper; 

import java.util.HashMap; 
import java.util.Map; 


public abstract class MultiDelegatingScript extends groovy.lang.Script { 

    private final Map<Object, MetaClass> delegateMap = new HashMap<>(); 

    protected MultiDelegatingScript() { 
    super(); 
    } 

    protected MultiDelegatingScript(Binding binding) { 
    super(binding); 
    } 

    public void setDelegate(Object delegate) { 
    this.delegateMap.put(delegate, InvokerHelper.getMetaClass(delegate.getClass())); 
    } 

    @Override 
    public Object invokeMethod(String name, Object args) { 
    for (Map.Entry<Object, MetaClass> delegate : this.delegateMap.entrySet()) { 
     try { 
     // Try to invoke the delegating method 
     return delegate.getValue().invokeMethod(delegate.getKey(), name, args); 
     } catch (MissingMethodException mme) { 
     // Method not found in delegating object -> try the next one 
     continue; 
     } 
    } 

    // No delegating method found -> invoke super class method for further handling 
    return super.invokeMethod(name, args); 
    } 

} 

は完全に私の期待を果たしていきます!

関連する問題