对于上下文,我正在开发一个名为Randoop的工具。我需要做的是能够使用Java代理在运行时替换某些方法调用。具体来说,我想用Random(0)替换对Random()的调用。
我有以下目录结构:
test_randoop/
randoop.jar
replacecall.jar
replacement_file.txt
ClassWithRandom.java
ClassWithRandom.class
replace/
java/
util/
Random.java
Random.class // created with "javac Random.java" command
我正在运行test_randoop
目录中的所有命令。
Random.java的内容是:
package replace.java.util;
public class Random {
/** Default mock for {@code Random()}. Replaces call with {@code Random(0)}. */
public static java.util.Random randomWithSeedZero() {
return new java.util.Random(0);
}
public static int returnZero() {
return 0;
}
}
我想在运行时使用以下行获取Random类,其中classname
定义为replace.java.util.Random
Class<?> methodClass = Class.forName(classname);
但是,从replacecall.jar文件调用此代码,该文件是我用来替换调用的Java代理。这似乎是一个问题,因为代理似乎并不知道replace.java.util.Random
类。
详细说明,我正在运行的Java程序使用以下命令执行:
java -ea -classpath .:randoop.jar -Xbootclasspath/a:/home/waylonh/test_randoop/replacecall.jar -javaagent:/home/waylonh/test_randoop/replacecall.jar="--replacement-file=replacement_file.txt --debug=true --verbose=true" randoop.main.Main gentests --testclass=ClassWithRandom --output-limit=10
问题是在类路径上找不到replace.java.util.Random
类,forName
方法抛出ClassNotFoundException
。
我试图在运行时使用以下代码段打印出系统类路径:
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
for (URL u : ((URLClassLoader) classLoader).getURLs()) {
System.out.println(u.getFile());
}
结果输出是:
/home/waylonh/test_randoop/
/home/waylonh/randoop/build/libs/randoop-all-3.1.5.jar
/home/waylonh/randoop/build/libs/replacecall-3.1.5.jar
我在这里可以缺少什么?是否必须为Java代理参数提供不同的类路径?为什么系统类加载器将test_randoop
目录列为类路径的一部分,但是找不到Random
中的类replace/java/util
?
Bootstrap类加载器(加载JDK类)和系统类加载器(加载应用程序类)是不同的东西。
默认情况下,Java代理程序由系统类加载器加载,并且可以访问-classpath
中指定的类。但是在你的情况下,由于-Xbootclasspath
选项,代理程序由引导程序类加载器加载,并且它不会从系统类加载器中看到类。
您基本上需要删除-Xbootclasspath
,以便代理也可以看到用户类。