相信不少Java开发人员都在使用
IntelliJ IDEA
进行开发,本人也使用很长时间的IntelliJ IDEA
。随着Visual Studio Code越来越火,中秋节假日期间想体验下,因此下载并针对VSCode进行了配置,将手头现有的一些项目导入进行了试用。
问题
刚开始环境配置还挺顺利的,很快就安装完了Java相关的环境,并写了个HelloWorld的类进行了测试,一切ok。接下来将手头的个别项目进行导入,并跑了下单元测试。诡异的情况出现了,在导入feature-flag项目之后,执行单元测试失败,但是通过mvn test和IDEA去执行都是正常的,报错信息如下:
Caused by: com.taobao.arthas.compiler.DynamicCompilerException: java.lang.RuntimeException: java.lang.RuntimeException: Wasn't able to open file:/Users/zhengzhq/Library/Application%20Support/Code/User/globalStorage/redhat.java/0.82.0/config_mac/org.eclipse.osgi/81/0/.cp/org as a jar file
at com.taobao.arthas.compiler.DynamicCompiler.build(DynamicCompiler.java:89)
at cn.zzq0324.feature.flag.support.JdkCompiler.compile(JdkCompiler.java:38)
at cn.zzq0324.feature.flag.FeatureFlagInstanceRegister.compileAndLoadClass(FeatureFlagInstanceRegister.java:83)
at cn.zzq0324.feature.flag.FeatureFlagInstanceRegister.dynamicLoadClassAndRegisterBean(FeatureFlagInstanceRegister.java:63)
at cn.zzq0324.feature.flag.FeatureFlagInstanceRegister.registerIfNotExist(FeatureFlagInstanceRegister.java:39)
... 31 more
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: Wasn't able to open file:/Users/zhengzhq/Library/Application%20Support/Code/User/globalStorage/redhat.java/0.82.0/config_mac/org.eclipse.osgi/81/0/.cp/org as a jar file
at com.sun.tools.javac.main.Main.compile(Main.java:559)
at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
at com.taobao.arthas.compiler.DynamicCompiler.build(DynamicCompiler.java:61)
一开始还以为是VSCode的vscode-java-test插件的bug导致的,因此提了issue,官方回复了,觉得这个问题是使用了arthas-memorycompiler导致的,需要联系对方解决,因此打了out-of-scope
的标签。想想好像也有道理,因此决定深入排查下问题,解决在VSCode上的解决问题。
排障
通过debug观察,发现arthas-memorycompiler在路径中包含空格、Unicode字符的时候会出现Bug,该Bug会导致找不到文件从而错误的执行到Jar的解析逻辑中,如下:
public List<JavaFileObject> find(String packageName) throws IOException {
String javaPackageName = packageName.replaceAll("\\.", "/");
List<JavaFileObject> result = new ArrayList<JavaFileObject>();
Enumeration<URL> urlEnumeration = classLoader.getResources(javaPackageName);
while (urlEnumeration.hasMoreElements()) { // one URL for each jar on the classpath that has the given package
URL packageFolderURL = urlEnumeration.nextElement();
result.addAll(listUnder(packageName, packageFolderURL));
}
return result;
}
private Collection<JavaFileObject> listUnder(String packageName, URL packageFolderURL) {
// 如果是路径带空格,此处就会找不到文件,调用isDirectory()就会返回false
File directory = new File(decode(packageFolderURL.getFile()));
if (directory.isDirectory()) { // browse local .class files - useful for local execution
return processDir(packageName, directory);
} else { // browse a jar file
return processJar(packageFolderURL);
} // maybe there can be something else for more involved class loaders
}
找到问题解决就方便了,通过URLDecoder.decode
就可以解决该问题了。最终提了Pull Request到arthas,并被官方采纳。顺便夸赞下,官方的Review速度很快,几个小时就Merged了。