我正在尝试使用Groovy以便将字符串转换为反射代码,但是我有“无此类属性”异常。
我尝试使所有变量都变为全局变量,更改反射代码并放入@Field表示法,但问题仍然存在。我将Groovy代码放入“ runTestSamples()”中。
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.jacoco.agent.AgentJar;
import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IClassCoverage;
import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.data.SessionInfoStore;
import org.jacoco.core.instr.Instrumenter;
import org.jacoco.core.runtime.IRuntime;
import org.jacoco.core.runtime.LoggerRuntime;
import org.jacoco.core.runtime.RuntimeData;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
public class Test2 {
private Runnable targetInstance;
public Class<?> targetClass;
private static HashMap<Integer, String> testSamples;
private static HashMap<String, Integer> coverageData;
public String targetName;
public IRuntime runtime;
public Instrumenter instr;
public InputStream original;
public byte[] instrumented;
public RuntimeData data;
public MemoryClassLoader memoryClassLoader;
static Test2 t2 = new Test2();
int a;
public static void main(String[] args) throws Exception {
testSamples = new HashMap<Integer, String>();
coverageData = new HashMap<String, Integer>();
try {
t2.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
public void execute() throws Exception {
testSamples = new HashMap<Integer, String>();
coverageData = new HashMap<String, Integer>();
targetName = SUTClass.class.getName();
runtime = new LoggerRuntime();
instr = new Instrumenter(runtime);
original = getTargetClass(targetName);
instrumented = instr.instrument(original, targetName);
original.close();
data = new RuntimeData();
runtime.startup(data);
memoryClassLoader = new MemoryClassLoader();
memoryClassLoader.addDefinition(targetName, instrumented);
targetClass = (Class<? extends Runnable>) memoryClassLoader.loadClass(targetName);
targetInstance = (Runnable) targetClass.newInstance();
// Test samples
runTestSamples();
targetInstance.run();
final ExecutionDataStore executionData = new ExecutionDataStore();
final SessionInfoStore sessionInfos = new SessionInfoStore();
data.collect(executionData, sessionInfos, false);
runtime.shutdown();
final CoverageBuilder coverageBuilder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executionData, coverageBuilder);
original = getTargetClass(targetName);
analyzer.analyzeClass(original, targetName);
original.close();
for (final IClassCoverage cc : coverageBuilder.getClasses()) {
coverageData.put("coveredInstructions", cc.getInstructionCounter().getCoveredCount());
}
System.out.println(coverageData.get("coveredInstructions"));
System.out.println(a);
}
public static class MemoryClassLoader extends ClassLoader {
private final Map<String, byte[]> definitions = new HashMap<String, byte[]>();
public void addDefinition(final String name, final byte[] bytes) {
definitions.put(name, bytes);
}
@Override
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
final byte[] bytes = definitions.get(name);
if (bytes != null) {
return defineClass(name, bytes, 0, bytes.length);
}
return super.loadClass(name, resolve);
}
}
private InputStream getTargetClass(final String name) {
final String resource = '/' + name.replace('.', '/') + ".class";
return getClass().getResourceAsStream(resource);
}
public void runTestSamples() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException,
NoSuchMethodException, SecurityException, ClassNotFoundException {
// Test case
targetClass.getMethod("f", int.class, int.class).invoke(targetInstance, 2, 9);
// Groovy String to code
Binding binding = new Binding();
GroovyShell shell = new GroovyShell(binding);
Object value = shell.evaluate("targetClass.getMethod(\"f\", int.class, int.class).invoke(targetInstance, 2, 9);");
}
}
groovy.lang.MissingPropertyException: No such property: targetClass for class: Script1
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:65)
at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:51)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:309)
at Script1.run(Script1.groovy:1)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:437)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:475)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:446)
at Test2.runTestSamples(Test2.java:119)
at Test2.execute(Test2.java:66)
at Test2.main(Test2.java:43)
答案 0 :(得分:0)
此代码中的问题:
Binding binding = new Binding();
GroovyShell shell = new GroovyShell(binding);
Object value = shell.evaluate("targetClass.getMethod(\"f\", int.class, int.class).invoke(targetInstance, 2, 9);");
调用shell.evaluate
时,请想象您调用的是绝对全新的类,而该类对您的当前变量一无所知,例如targetClass
因此,GroovyShell
告诉您没有这样的属性:targetClass
要解决此问题-您只需填充绑定-传递变量值和名称,这些值和名称应在shell.evaluate(...)
内部可见。
Binding binding = new Binding();
binding.setVariable("target", targetClass) //pass targetClass as target variable name
binding.setVariable("instance", targetInstance)
GroovyShell shell = new GroovyShell(binding);
Object value = shell.evaluate("target.getMethod(\"f\", int.class, int.class).invoke(instance, 2, 9)");
另一点-groovy已经是动态语言,您可以从中简化嵌套脚本:
target.getMethod("f", int.class, int.class).invoke(instance, 2, 9)
对此:
instance."f"(2, 9)
最后也许您不需要使用groovyshell,因为以下代码动态调用了该方法:
class A{
def f(int a, int b){ a+b }
}
def instance = new A()
def method = "f"
def params = [2,9]
println instance."${method}"(params)