1。背景
私のmavenプロジェクトには、jars
とwars
を含む多数のモジュールとサブモジュールがあり、すべてが機能します。サーバーに問題なく展開することもできます。
私は このmavenの名前変換 に従うことを決定しました。適切な名前を付けるために、project.name
およびproject.build.finalName
を使用していくつかのテストを行っています。
ルートアーティファクトのproject.name
を作成するために定義したパターンはcompany-${project.artifactId}
であり、モジュールとサブモジュールのパターンは${project.parent.name}-${project.artifactId}
です。
project.build.finalName
のパターンは${project.name}-${project.version}
です。
しかし、これらのファイルを生成する代わりに、mavenはStackOverflowError
をくれます。
2。エラーを再現する例
この例はgithubからクローンできます: https://github.com/pauloleitemoreira/company-any-artifact
Githubには、このエラーを再現する master
ブランチがあります。そして only-modules
ブランチがあります。これは${project.parent.name}
を使用してjar finalName
を生成する実用的な例です。
ルートpomアーティファクトが1つ、pomモジュールが1つ、サブモジュールが1つあるMavenプロジェクトを考えてみましょう。
-any-artifact
|
|-any-module
|
|-any-submodule
2.1任意のアーティファクト
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.Apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.Apache.org/POM/4.0.0 http://maven.Apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.company</groupId>
<artifactId>any-artifact</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>company-${project.artifactId}</name>
<modules>
<module>any-module</module>
</modules>
<!-- if remove finalName, maven will not throw StackOverflow error -->
<build>
<finalName>${project.name}-${project.version}</finalName>
</build>
</project>
2.2 any-module
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.Apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.Apache.org/POM/4.0.0 http://maven.Apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>any-artifact</artifactId>
<groupId>com.company</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.company.any-artifact</groupId>
<artifactId>any-module</artifactId>
<packaging>pom</packaging>
<name>${project.parent.name}-${project.artifactId}</name>
<modules>
<module>any-submodule</module>
</modules>
</project>
2.3 any-submodule
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.Apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.Apache.org/POM/4.0.0 http://maven.Apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>any-module</artifactId>
<groupId>com.company.any-artifact</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.company.any-artifact.any-module</groupId>
<artifactId>any-submodule</artifactId>
<name>${project.parent.name}-${project.artifactId}</name>
</project>
3。問題
mvn clean install
を試そうとすると、mavenはStackOverflowError
をくれます:
Exception in thread "main" Java.lang.StackOverflowError
at org.codehaus.plexus.util.StringUtils.isEmpty(StringUtils.Java:177)
at org.codehaus.plexus.util.introspection.ReflectionValueExtractor.evaluate(ReflectionValueExtractor.Java:194)
at org.codehaus.plexus.util.introspection.ReflectionValueExtractor.evaluate(ReflectionValueExtractor.Java:163)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:266)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:143)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:174)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:143)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:429)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:143)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:174)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:143)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:429)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:143)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:174)
at org.Apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.Java:143)
エラーが発生するのは、サブモジュールで作業している場合のみであることを知っておくことが重要です。ルートPOMアーティファクトとjarモジュールを使用してプロジェクトを作成しても、エラーは発生しません。
4。質問
サブモジュールを使用しているときにのみこのエラーが発生するのはなぜですか?
私の問題を解決するための提案はありますか?忘れて、project.name
とproject.build.fileName
をプロジェクトごとに手動で設定し、必要なパターンに従ってください。
重要な更新:
一部の回答は&{parent.name}
を使用するように言っていますが、機能しません。賞金を伴う質問です。この質問に答える前に、Maven version 3.3.9
でソリューションをテストすることを検討してください。
Mavenバージョン3.3.9
Edit-エラーが発生した段階で質問に詳細を追加すると、問題はprepare-package
フェーズですが、StackOverflowはプロジェクトのMavenライフサイクルのpackage
フェーズで発生します。
あなたの質問に対する厳密な答えは、_${project.parent.name}
_がモデル補間プロセスの一部として解決されないことです。そして、コードの完全に異なる場所にStackOverflowError
があります。つまり、プロジェクトの最終的なJARをビルドするときです。
ここで何が起こるかです。プロジェクトでMavenコマンドを起動する場合、最初に実行するアクションは、プロジェクトの効果的なモデルを作成することです。つまり、POMファイルの読み取り、アクティブ化されたプロファイルの推論、継承の適用、プロパティの補間の実行など、プロジェクトの最終的なMavenモデルを構築します。この作業は Maven Model Builder コンポーネントによって行われます。
モデルを構築するプロセスはかなり複雑で、多くのステップが2つのフェーズに分かれている可能性がありますが、ここで注目する部分は モデル補間 部分です。これは、Mavenがモデルで_${...}
_によって示されるすべてのトークンを計算値に置き換えるときです。プロファイルが注入され、継承が実行された後に発生します。その時点では、MavenProject
オブジェクトで表されるMavenプロジェクトはまだ存在せず、Model
のみがビルドされています。そして、モデルからMavenプロジェクトの構築を開始できるのは、完全なモデルを作成した後です。
したがって、補間が行われるとき、それはPOMファイルに存在する情報に関してのみ理由であり、唯一の有効な値は モデル参照で言及された の値のみです。 (この置き換えは、ソースコードを確認したい場合、 StringSearchModelInterpolator
クラスによって実行されます。)特に、モデルの_<parent>
_要素がnotには、親モデルの名前が含まれます。 MavenのクラスModel
は実際にはソース_.mdo
_ファイルから Modello で生成され、そのソースは groupId
、artifactId
、version
およびrelativePath
を定義するだけです( _<parent>
_要素のカスタムid
)。これも表示されます ドキュメント内 。
これらすべての結果、モデルの補間が実行された後、トークン_${project.parent.name}
_は置き換えられません。さらに、それから構築されたMavenProject
には、置き換えられない_${project.parent.name}
_を含む名前が付けられます。これはログで確認できます。サンプルプロジェクトでは、
_[INFO] Reactor Build Order:
[INFO]
[INFO] company-any-artifact
[INFO] ${project.parent.name}-any-module
[INFO] ${project.parent.name}-any-submodule
_
Mavenがプロジェクトの実際の名前_any-module
_を_${project.parent.name}-any-module
_と見なすことを意味します。
現在、reactor内のすべてのプロジェクトが正しく作成され、コンパイルさえされています。実際、すべては理論的には問題なく機能するはずですが、プロジェクト自体の名前は完全に不完全です。しかし、_maven-jar-plugin
_を使用したJARの作成で失敗するという奇妙なケースがあります。この例では、ビルドは次のログで失敗します。
_[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ any-submodule ---
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] company-any-artifact ............................... SUCCESS [ 0.171 s]
[INFO] ${project.parent.name}-any-module .................. SUCCESS [ 0.002 s]
[INFO] ${project.parent.name}-any-submodule ............... FAILURE [ 0.987 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
_
モデルが構築された後、何かがうまくいかなかったことを意味します。そしてその理由は、プラグイン プロジェクトの名前をパラメーターとして挿入する :
_/** * Name of the generated JAR. * * @parameter alias="jarName" expression="${jar.finalName}" default-value="${project.build.finalName}" * @required */ private String finalName;
_
サブモジュールの生成されたJAR名のデフォルト値として_project.build.finalName
_に注意してください。この注入、および変数の補間は、 PluginParameterExpressionEvaluator
と呼ばれる別のクラスによって行われます。
これで何が起こるか:
any-submodule
_のJARプラグインは、_${project.parent.name}-any-submodule
_という名前のプロジェクトの最終名を挿入します。<finalName>
_の宣言に感謝します。これは_<finalName>${project.name}-${project.version}</finalName>
_を継承します。${project.name}
_に対して_any-submodule
_を補間しようとしています。${project.parent.name}-any-submodule
_に解決されます。${project.parent.name}
_に対して_any-submodule
_を補間しようとしています。これは正しく機能します。MavenProject
がビルドされ、プロジェクトインスタンスで getParent()
が呼び出され、具体的なMaven親プロジェクトが返されます。そのため、_${project.parent.name}
_は、実際には_any-module
_である_${project.parent.name}-any-module
_の名前を解決しようとします。${project.parent.name}-any-module
_、を補間しようとしていますが、それでも_any-submodule
_プロジェクトインスタンスを使用しています。 PluginParameterExpressionEvaluator
の場合、トークンを評価するルート_"project"
_は変更されていません。${project.parent.name}
_で_any-submodule
_を補間しようとするようになりました。これもまた正しく機能し、_${project.parent.name}-any-module
_を返します。${project.parent.name}
_で_any-submodule
_を補間しようとするようになり、動作して_${project.parent.name}-any-module
_を返すため、_${project.parent.name}
_...を評価しようとします.そして、ここで無限の再帰が発生していることがわかります。これにより、StackOverflowError
が生成されます。これはPluginParameterExpressionEvaluator
のバグですか?これは不明確です。そもそも正しく置き換えられなかったモデル値が原因です。理論的には、常に現在のプロジェクトで作業するのではなく、_${project.parent}
_を評価する特別なケースを処理して、この親プロジェクトで作業する新しいPluginParameterExpressionEvaluator
を作成できます。これについて強く感じた場合は、自由に作成してください JIRAの問題 。
上記で述べたことで、このケースでそれが機能する理由を推測できます。 Maven Jarプラグインに挿入する必要があるため、最終名を評価するためにMavenが何を行う必要があるかを考えてみましょう。
any-module
_のJARプラグインは、_${project.parent.name}-any-module
_という名前のプロジェクトの最終名を挿入します。<finalName>
_の宣言に感謝します。これは_<finalName>${project.name}-${project.version}</finalName>
_を継承します。${project.name}
_に対して_any-module
_を補間しようとしています。${project.parent.name}-any-module
_に解決されます。${project.parent.name}
_に対して_any-module
_を補間しようとしています。以前と同じように、これは正しく動作します。MavenProject
がビルドされ、プロジェクトインスタンスで getParent()
が呼び出され、具体的なMaven親プロジェクトが返されます。そのため、_${project.parent.name}
_は、実際には_any-artifact
_である_company-any-artifact
_の名前を解決しようとします。そして、エラーはありません。
project.parent.nameとparent.nameの違いと私の回答で述べたように、pom.xml でのfinalNameの使用
最初に基本を見てみましょう:
POMリファレンス に記載されているとおり:
finalName:これは、最終的にビルドされたときのバンドルされたプロジェクトの名前です(たとえば、my-project-1.0.jarなどのファイル拡張子を除きます)。デフォルトは$ {artifactId}-$ {version}です。
name:プロジェクトは、artifactIdを超えて、会話型の名前を持つ傾向があります。
したがって、これら2つには異なる用途があります。
name
は情報提供のみを目的としており、主に生成されたドキュメントとビルドログで使用されます。継承も使用もされていません。これは人間が読める文字列であり、スペースやファイル名に使用できない文字など、任意の文字を含めることができます。したがって、これは有効です:<name>My Turbo Project on Speed!</name>
。これは明らかに、少なくともアーティファクトの疑わしいファイル名です。
上記のように、finalName
は生成されたアーティファクトの名前です。is継承されるため、通常はプロパティに依存する必要があります。本当に便利なオプションは、デフォルトの${artifactId}-${version}
とバージョンのない${artifactId}
の2つだけです。それ以外はすべて混乱を招きます(foo
というプロジェクトがアーティファクトを作成するbar.jar
など)。実は私のターボプロジェクト!これは有効なファイル名なので有効ですが、実際には、そのようなファイル名はかなり使い物になりがちです(たとえば、!を含むファイル名をbashから指定してみてください)。
したがって、Stackoverflowが発生する理由について:
name
は継承されませんproject.parent.name
も補間時に評価されません。名前は子から完全に見えない数少ないプロパティの1つだからです。parent.name
は、以前のMavenバージョンで実際に機能していましたが、バグが原因でさらに機能しました(先頭のproject
なしでプロパティにアクセスするのもdeprecatedです)。any-submodule
の効果的なpomで、finalName
の値は(mvn help:effective-pom
で試してください)です:${project.parent.name}-any-submodule
これまでのところ悪い。 StackOverflowの理由がここに来る
Mavenには遅延補間と呼ばれる追加機能があり、プラグインパラメータの値が実際に使用されたときにそれらを評価します。これにより、モデルの一部ではないがライフサイクルの早い段階でプラグインによって生成されたプロパティをプラウで使用できるようになります(これにより、たとえばプラグインが最終的な名前にgitリビジョンを提供できるようになります)。
だから何が起こるのですか:
edit:エラーの実際の理由をより明確にしました(コメントを参照):
@Parameter( defaultValue = "${project.build.finalName}", readonly = true )
PluginParameterExpressionEvaluator
が起動し、最終的な名前(${project.parent.name}-any-submodule
、プロパティ式$ {project.parent.name}を含む)を評価しようとします。${project.parent.name}-any-module
)を返します。${project.parent.name}-any-module
を(もう一度)返します。プロパティは常に現在のプロジェクトに対して解決されているので、サイクルが再び始まります。残念ながらできません。
プロジェクトごとにname
(およびartifactId
)を明示的に指定する必要があります。回避策はありません。
次に、couldfinalName
に依存させます。しかし、私はそれに対して助言します( project.parent.nameとparent.nameの違いとpom.xml でのfinalNameの使用の違いを参照してください)
このように最終的な名前を変更する際の問題は、ローカルで作成されたアーティファクトとリポジトリ内のアーティファクトの名前が異なるため、ローカルではアーティファクトの名前はany-artifact-any-module-any-submodule.jar
ですが、リポジトリ内のアーティファクト名はany-submodule.jar
のままです。
<artifactId>artifact-anymodule-anysubmodule</artifactId>
。anymodule
のままにすることができますが、モジュールの実際のArtifactIdである必要はありません!name
を使用して人間が読めるようにします。これにより、視覚的に魅力的なものを検討できます(これはビルドログに表示される名前であるため)<name>Artifact :: AnyModule :: AnySubModule</name>
。これは属性継承の問題です。
_${parent.name}
_の代わりに_${project.parent.name}
_を使用してください。
見てください 親POMで宣言されたプロジェクト名は、web.xmlでフィルタリングされたモジュールで展開されていません 。
- -更新 - -
Benjamin Bentmann(maven committier)は、「一般的に、_${project.parent.*}
_形式の式は特定のビルド状態に依存し、一般にPOM全体で機能せず、驚きをもたらすため、不適切な方法です」と述べています。
https://issues.Apache.org/jira/browse/MNG-5126?jql=text%20~%20%22parent%20name%22
多分あなたは_${project.parent.*}
_を使うのが良い方法だと考えるべきです。