2017-04-27 33 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将完全满足了我的预期!