2017-04-27 32 views
0

我有一個Java應用程序,我想添加一個擴展來執行groovy腳本。到目前爲止,解析,編譯和執行都不是問題!處理多個代表

爲簡化起見,我希望Groovy語法儘可能簡單(例如,不需要OO技能)。此外,groovy腳本應能夠訪問由java類初始化的庫函數。這是@Delegate發揮作用的部分!

目前,我有兩個不同的解決方案,都不能完全令人滿意,我想出了:

GroovyService.java

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() { /* ... */ } 

} 

解決方案#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() 
} 

這種解決方案的優點是我可以爲任何服務(服務*)使用固定的成員名稱,但我對語法印象不深。

Groovy的腳本的用法如下:

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

我想出了一個很好的解決方案,我寫了一個類似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); 
    } 

} 

使用這個類來代替DelegatingScript將完全滿足了我的預期!