Maven故障排查 博客分类: pinpoint
最近在使用pinpoint-2.7,在调试某些模块源码时,发现在Maven-Install步骤总是会失败。
但Maven的错误提示语焉不详。例如下面:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.5.1:testCompile (default-testCompile) on project pinpoint-bootstrap: Compilation failure -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging.
即使我们打开Maven的 Debug Output(-X)详细错误日志,仍然什么都看不到。
郁闷之极。
实在没有办法,只能祭出“断点调试”这最后一步棋了!
第一步,我们找到出错的插件和目标:org.apache.maven.plugins:maven-compiler-plugin:3.5.1:testCompile
第二步,新建一个demo工程,我们把错误插件添加到Maven依赖中来
<dependency> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <scope>provided</scope> </dependency>
第三步,找到maven-compiler-plugin-3.5.1.jar中插件定义plugin.xml文件,搜索“testCompile”目标,
找到它的实现类:
<implementation>org.apache.maven.plugin.compiler.TestCompilerMojo</implementation>
然后,在TestCompilerMojo的execute()方法上打上断点
第四步,首先在项目上右键:Run As - Maven-Install,产生一个运行配置。
然后,在Eclipse的调试配置中,找到刚产生的运行配置,注意在“Maven Build”下面。
在目标中输入“clean install”
点击调试按钮。这时候,Maven运行会停在断点位置。但是会找不到源代码。
第五步,我们把源代码关联进来。首先在demo项目上,执行Maven - Download Sources,
把依赖部分的源码下载下来。
然后,回到上一步的调试配置,打开“Source”标签页,用Add方法添加源码搜索路径:
M2_REPO/org/apache/maven/plugins/maven-compiler-plugin/3.5.1/maven-compiler-plugin-3.5.1.jar
注意,不要上面添加的不是-sources.jar文件。(好处是调试时,在display视图中可以直接执行代码片段)
第六步,重新执行debug clean install,这时候,我们发现断点停留在TestCompilerMojo.execute()方法
对应行。我们沿着调用栈向上寻找,找到最近的catch(Exception)的代码位置,我们加上断点。
这儿找到的位置是:MojoExecutor.java
try { pluginManager.executeMojo( session, mojoExecution ); } catch ( MojoFailureException | PluginManagerException | PluginConfigurationException | MojoExecutionException e ) { throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e ); }
第七步,继续执行,这时候,我们发现断点停留在catch后的位置,
我们点开变量视图,查看此时的异常对象类型,发现是:org.apache.maven.plugin.compiler.CompilationFailureException
然后,我们进入断点视图,添加对应的“异常断点”。
第八步,重新开始调试。这时候我们发现断点停留在org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute()方法上。
根据代码,我们知道,当warnings为空的时候,将丢出此异常。
继续向上快速阅读源码,我们知道 当compilerResult返回false时,会触发编译失败异常,这也很容易理解。
第九步,我们找到CompilerResult这个类的代码(maven会自动下载打开类的代码),
找到success字段,将这个字段的写操作添加到断点中。
第十步,重启调试,这次断点停留在CompilerResult的构造函数(<init>方法)上。
我们查看java栈,找到下一个调用方法,发现断点停留在:
org.codehaus.plexus.compiler.javac.JavacCompiler.compileOutOfProcess()方法。
这也很容易理解了,Maven 编译过程调用了外部的JavaC命令行。
第十一步,我们找到了核心执行语句:
returnCode = CommandLineUtils.executeCommandLine( cli, out, err );
这时候查看 cli 的参数,其值类似于:
cmd.exe /X /C "D:\eclipse4oschina\jdk1.6.0_23\bin\javac @C:/Users/caohj/AppData/Local/Temp/org.codehaus.plexus.compiler.javac.JavacCompiler8877254923779120414arguments"
第十二步,我们打开一个新的CMD窗口,把cmd命令拷贝出来,放在命令行执行。
这时候我们终于看到了错误提示:
错误:读取 D:\m2\net\bytebuddy\byte-buddy\1.6.11\byte-buddy-1.6.11.jar 时出错; invalid LOC header (bad signature) 1 错误
原来,罪魁祸首是Maven在下载byte-buddy库时出现了错误。
我们删除对应的JAR,然后回到Eclipse中,在项目上右键 Maven - Update Project,重新下载需要的JAR
我们发现,两次下载的JAR文件果然大小不一样。
重新执行 Maven-Install, 故障排除。
---------------------------------------------------------
故障排除后,我们来看一下,为什么Maven没有提示出编译错误呢?
我们重新把错误的byte-buddy JAR包还原,再次进入调试。
断点跟踪,终于发现问题所在:plexus-compiler-javac/2.7版的
org.codehaus.plexus.compiler.javac.JavacCompiler.parseModernStream()方法
在解析JavaC命令行错误时,有一处关键语句:
if ( ( buffer.length() == 0 ) && line.startsWith( "error: " ) ) { errors.add( new CompilerMessage( line, true ) ); }
但是命令行返回的提示却是:
错误:读取 D:\m2\net\bytebuddy\byte-buddy\1.6.11\byte-buddy-1.6.11.jar 时出错;invalid LOC header (bad signature)
“error:” 和 "错误:" ----- 这可能是对中文版JavaC提示考虑不足吧!
推荐阅读
-
Maven故障排查 博客分类: pinpoint
-
Maven故障排查 博客分类: pinpoint
-
使用maven添加dom4j依赖 博客分类: dom4j dom4j
-
使用maven打出独立应用程序的jar包 博客分类: Java maven配置管理log4jXMLApache
-
使用maven打出独立应用程序的jar包 博客分类: Java maven配置管理log4jXMLApache
-
在 IntelliJ IDEA 中加快 Maven 项目的单元测试编译速度 博客分类: Java
-
在 IntelliJ IDEA 中加快 Maven 项目的单元测试编译速度 博客分类: Java
-
Gradle 实践 博客分类: 开源框架 gradle maven ant
-
Gradle 实践 博客分类: 开源框架 gradle maven ant
-
在构建单一 Jar 包时,Maven Assembly 和 Shade 插件的不同之处 博客分类: 开源框架