记arthas-memorycompiler在VSCode报错


相信不少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了。


文章作者: zzq0324
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 zzq0324 !
  目录