Maven plugin throw some exception
eclipseでincubator-parquet-mrのコードをビルドする為に、mvn eclipse:eclipse
を実行したところ、以下のエラーが出ました。
[ERROR] Failed to execute goal com.twitter:scrooge-maven-plugin:3.9.0:compile (thrift-sources) on project parquet-scrooge: Execution thrift-sources of goal com.twitter:scrooge-maven-plugin:3.9.0:compile failed. NullPointerException -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal com.twitter:scrooge-maven-plugin:3.9.0:compile (thrift-sources) on project parquet-scrooge: Execution thrift-sources of goal com.twitter:scrooge-maven-plugin:3.9.0:compile failed.
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:224)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
at org.apache.maven.lifecycle.internal.MojoExecutor.executeForkedExecutions(MojoExecutor.java:364)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:198)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:120)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:347)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:154)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:582)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:214)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:158)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: org.apache.maven.plugin.PluginExecutionException: Execution thrift-sources of goal com.twitter:scrooge-maven-plugin:3.9.0:compile failed.
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:143)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
... 23 more
Caused by: java.lang.NullPointerException
at com.twitter.AbstractMavenScroogeMojo.findThriftDependencies(AbstractMavenScroogeMojo.java:324)
at com.twitter.AbstractMavenScroogeMojo.findThriftFiles(AbstractMavenScroogeMojo.java:292)
at com.twitter.AbstractMavenScroogeMojo.execute(AbstractMavenScroogeMojo.java:191)
at com.twitter.MavenScroogeCompileMojo.execute(MavenScroogeCompileMojo.java:22)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:132)
com.twitter:scrooge-maven-plugin:3.9.0
のAbstractMavenScroogeMojo.java:324
でNullPointerException
が出ているようです。原因を調べる為、このMavenプラグインのデバッグにトライしました。
mvnDebug
Mavenプラグインのデバッグについてググったところ、mvnDebug
を使うとできるようなので、早速試してみました。このmvnDebug
はMavenにバンドルされているので、事前に何かをインストールする必要はありません。
$ mvnDebug eclipse:eclipse
Preparing to Execute Maven in Debug Mode
Listening for transport dt_socket at address: 8000
なるほど、mvnの実行プロセスにアタッチできるようです。そうなるとこのプラグインのソースコードが欲しいので、https://oss.sonatype.org/からcom.twitter:scrooge-maven-plugin:3.9.0
のソースコードをダウンロードし、jar xvf
で展開しておきます。
jdb
次にjdbでmvnのプロセスにアタッチします。
$ jdb -sourcepath . -attach 8000
uncaught java.lang.Throwable を設定しました
保留した uncaught java.lang.Throwable を設定しました
jdb の初期化中です...
>
VM が起動しました: 現行の呼び出しスタックにはフレームがありません
この状態ではまだプロセスの実行が止まっている状態なので、NPEが発生している箇所にブレークポイントを設定します。
main[1] stop at com.twitter.AbstractMavenScroogeMojo:324
ブレークポイント com.twitter.AbstractMavenScroogeMojo:324 を保留しています。
クラスがロードされた後に設定されます。
そしてプロセスを実行します。
main[1] run
すると、ブレークポイントを設定した問題箇所で停止します。
> 保留した ブレークポイント com.twitter.AbstractMavenScroogeMojo:324 を設定しました
ブレークポイントのヒット: "スレッド=main", com.twitter.AbstractMavenScroogeMojo.findThriftDependencies(), line=324 bci=170
324 for (String name : depTrail) {
ここでNPEが発生するということは、depTrail
がnullということになります。depTrail
に何が設定されているかprint depTrail
で確認します。
main[1] print depTrail
depTrail = "[com.twitter:parquet-scrooge:jar:1.6.1-SNAPSHOT, com.twitter:parquet-column:jar:1.6.1-SNAPSHOT, commons-codec:commons-codec:jar:1.5]"
問題なさそうです。cont
で先に進めます。
main[1] cont
>
ブレークポイントのヒット: "スレッド=main", com.twitter.AbstractMavenScroogeMojo.findThriftDependencies(), line=324 bci=170
324 for (String name : depTrail) {
またprint depTrails
で値をチェックします。
main[1] print depTrail
depTrail = "[com.twitter:parquet-scrooge:jar:1.6.1-SNAPSHOT, com.twitter:parquet-thrift:jar:1.6.1-SNAPSHOT, com.twitter.elephantbird:elephant-bird-core:jar:4.4, com.google.guava:guava:jar:11.0.1, com.google.code.findbugs:jsr305:jar:1.3.9]"
問題ないです。cont
で先に進めます。
main[1] cont
>
ブレークポイントのヒット: "スレッド=main", com.twitter.AbstractMavenScroogeMojo.findThriftDependencies(), line=324 bci=170
324 for (String name : depTrail) {
main[1] print depTrail
depTrail = null
depTrail
がnullになりました。この箇所でNPEが発生することになります。locals
で変数の状態を確認します。
main[1] locals
メソッド引数:
whitelist = instance of java.util.HashSet(id=2365)
ローカル変数:
thriftDependencies = instance of java.util.HashSet(id=2366)
deps = instance of java.util.HashSet(id=2367)
depsMap = instance of java.util.HashMap(id=2368)
i$ = instance of java.util.HashMap$KeyIterator(id=2369)
artifact = instance of org.apache.maven.artifact.DefaultArtifact(id=2370)
depTrail = null
depTrail
は多分pom.xml
のdependencyに関する情報だと考えられます。そこでdumpコマンドを使ってartifact
という変数の内容を見てみます。
main[1] dump artifact
artifact = {
groupId: "commons-httpclient"
artifactId: "commons-httpclient"
baseVersion: "3.0.1"
type: "jar"
classifier: null
scope: "test"
file: null
repository: null
downloadUrl: null
dependencyFilter: null
artifactHandler: instance of org.apache.maven.artifact.handler.DefaultArtifactHandler$__sisu12(id=3036)
dependencyTrail: null
version: "3.0.1"
versionRange: instance of org.apache.maven.artifact.versioning.VersionRange(id=3037)
resolved: false
release: false
availableVersions: null
metadataMap: null
optional: false
}
commons-httpclient
のdependencyが取得できなかったように見えます。このcommons-httpclient
のjarファイルを見てみるとpom.xml
ではなくproject.xml
が入っており、かなり古いモジュールであることから、dependencyがうまく取得できなかったと考えられます。
こういったartifactがあることを考えると、depTrail
がnullであるケースに対応する必要があります。scrooge-maven-plugin
のgithubのコードを見ると、この問題はすでに修正されていました。
scrooge-maven-plugin/src/main/java/com/twitter/AbstractMavenScroogeMojo.java:
1 // depTrail can be null sometimes, which seems like a maven bug
2 if (depTrail != null) {
3 for (String name : depTrail) {
4 Artifact dep = depsMap.get(name);
5 if (dep != null && "idl".equals(dep.getClassifier()) && whitelist.contains(dep.getArtifactId())) {
6 thriftDependencies.add(artifact);
7 break;
8 }
9 }
10 }
実際にscrooge-maven-plugin
のバージョンを上げてみたところ、エラーは発生せず正常に完了しました。
Conclusion
mvnDebugを使ってMaven Pluginをデバッグしました。
mvnまわりでエラーがでると調べるのが面倒ですが、今回のようにコードを修正しなくても回避できる手段が見つかることもあるので、取りあえずパッと見てみるのも良いかな、と思います。