我理解时髦的基础知识 - 以及封闭......
我试图从java调用groovy:
// Patient.java
public class Patient {
//... other data
private Map<String, String> attribStore = new HashMap<String,String>();
// getters/setters for attribStore omitted
public void addAttribute(String key, String val) {
if (!attribStore.containsKey(key)) {
attribStore.put(key, val);
}
}
// GroovyHelper.java
public class GroovyHelper {
private String codeSnippet; // groovy script code
public String evaluateSnippetToString(Binding binding) {
addMethodMissingHandler();
GroovyShell shell = createGroovyShell(binding);
Object result = shell.evaluate(codeSnippet);
return result.toString();
}
// installs a patient in the binding - accesses the patient
// attribStore from groovy
// The missing method is used to create an "attribute" i.e.
// a (key,val) pair in the patient map
private void addMethodMissingHandler() {
codeSnippet = "def attribStore = p.getAttribStore();\n"
+ "Patient.metaClass.methodMissing = \n{"
+ " String methodName, args -> \n"
+ "methodName = methodName.replaceFirst(/^get/, '');\n"
+ "def attrib = methodName[0].toLowerCase() + methodName.substring(1);\n"
+ "if (!attribStore.containsKey(attrib)) { attribStore[attrib] = '0'; }\n"
+ "return attribStore[attrib]; \n" + "}\n" + codeSnippet;
}
}
// junit测试代码
private Patient p;
private Binding binding;
private GroovyHelper gh;
@Before
public void init() {
p = new PatientBuilder().build();
binding = new Binding();
binding.setVariable("p", p);
gh = new GroovyHelper();
}
@Test //passes
public void testPopulatePatientAttribStore() throws Exception {
p.addAttribute("xyz", "4");
gh.setCodeSnippet("p.getXyz()");
gh.evaluateSnippetToString(binding);
}
@Test
public void testGroovy() throws Exception {
Binding binding = new Binding();
binding.setVariable("p", new Patient()); // new patient
p.addAttribute("xyz", "9");
GroovyShell gs1 = new GroovyShell(binding);
assertEquals("9", gs1.evaluate("p.getXyz()")); // fails??? - expected: <[9]> but was: <[4]>
}
我的问题是 - 是否关闭了先前绑定的属性存储?
究竟发生了什么?
为所有冗长的代码道歉 - 我为此工作了
- 减少不相关的代码
将它缩小到最小 - 任何指针,“更多阅读要做”提示?
答案 0 :(得分:1)
我认为问题的一部分是您在methodMissing
元类中创建Patient
,该代词委托给一位特定患者的attribStore
。我会以不同的方式解决问题 - 是否可以直接在methodMissing
类本身中实现Patient
?
public class Patient {
// other members as before
public Object methodMissing(String name, Object[] args) {
if(name != null && name.startsWith("get") && name.length() > 3) {
String attrName = name.substring(3,1).toLowerCase() + name.substring(4);
addAttribute(attrName, "0");
return attribStore.get(attrName);
} else {
throw new MissingMethodException(name, this.getClass(), args);
}
}
}
或者,如果这不是一个选项,你可以在Groovy中实现GroovyHelper
类(使用groovyc编译它,你可以从Java调用它与任何Java类相同)吗?
public class GroovyHelper {
static {
// add a methodMissing to the Patient metaclass
Patient.metaClass.methodMissing = { String name, args ->
if(name?.startsWith("get") && name.length() > 3) {
String attrName = name.substring(3,1).toLowerCase() + name.substring(4)
// delegate here is the particular Patient instance on which the
// missing method call was made
delegate.addAttribute(attrName, "0")
return delegate.attribStore[attrName];
} else {
throw new MissingMethodException(name, this.getClass(), args);
}
}
}
private String codeSnippet // groovy script code
public String evaluateSnippetToString(Binding binding) {
GroovyShell shell = createGroovyShell(binding)
Object result = shell.evaluate(codeSnippet)
return result.toString()
}
}
答案 1 :(得分:0)
Patient
的MetaClass看起来确实存在b / w GroovyShell
次运行 - MetaClassRegistry可能是单例,因此可以在类加载器或JVM的生命周期内生存(可以现在还要仔细考虑一下JVM的工作原理。而且,正如您所建议的那样,我相信您的methodMissing
闭包会围绕它最初得到的attribStore
变量。 (一个快速测试似乎表明你应该有权访问该闭包内的绑定中的p
。我猜你试过这个并且它没有用?)。在拆解方法中,每次测试后,一个选项可能是从Patient
强制remove the MetaClass。