我编写了一个插件,它将类文件列表(编译Java项目)作为输入,并运行与这些类相关的测试用例。我使用类加载器来加载类,并使用JUnitCore()来运行测试用例。下面的代码工作正常,运行输入类时没有问题。
Class<?> clazz = Class.forName(className);
Request request = Request.aClass(clazz);
Result result = new JUnitCore().run(request);
但是,在我的程序中,上面的代码应该为类似的类运行数千次。为简单起见假设我们只有一个类,第一步是编译类,然后如果没有编译器错误它被复制到插件的bin目录然后调用我的程序并检查它通过了所有测试用例。
在下一次迭代中,原始源代码会自动更改,然后进行编译,如果没有编译器错误,则会复制并再次运行测试用例。这个过程可以运行数千次以获得所需的结果。 [在某些情况下甚至数小时]
然而,问题是类加载器使用编译器类的第一个版本,并且在下一次迭代中它不加载新版本并仍然使用前一版本。我发现如果我在每次迭代中在复制指令之前添加 Thread.sleep(1000),那么它可以找到正确的版本。
首先,为什么我需要在复制之前暂停 并且在复制之后?我希望在类加载器想要加载它们之前复制期间可能没有完成文件,而classloader使用以前的版本。但是,正如我所说,当我在复制之前添加暂停时,它工作正常,并且它在复制后添加暂停时使用以前的版本。
其次,在我的程序中使用sleep并不是一个好主意。我的插件在最好的情况下可能会工作几个小时来找到所需的结果,如果我想在每次迭代中添加一个睡眠,那么结果需要数天。因此,我更喜欢没有睡眠的解决方案。如果有人知道如何在没有Thread.sleep的情况下复制上述问题,请告诉我。
答案 0 :(得分:0)
我找到了解决方案。事实上,在程序更改后,我首先刷新项目,然后复制文件。但是,问题是JDT在复制之前不会重新编译和重建索引。所以我需要等待重建完成,然后再复制。这就是为什么复制前的 Thread.sleep 可以解决问题的原因。 但是,更好的解决方案是在刷新项目期间使用以下说明。
try {
project.refreshLocal(IResource.DEPTH_INFINITE, null);
IJobManager jobManager = Job.getJobManager();
jobManager.join(ResourcesPlugin.FAMILY_AUTO_BUILD, null);
} catch (CoreException | OperationCanceledException | InterruptedException e) {
e.printStackTrace();
}
以上几行解决了这个问题。