web-dev-qa-db-ja.com

明示的なfinalNameを持つMavenは正しく機能しません

1。背景

私のmavenプロジェクトには、jarswarsを含む多数のモジュールとサブモジュールがあり、すべてが機能します。サーバーに問題なく展開することもできます。

私は このmavenの名前変換 に従うことを決定しました。適切な名前を付けるために、project.nameおよびproject.build.finalNameを使用していくつかのテストを行っています。

ルートアーティファクトのproject.nameを作成するために定義したパターンはcompany-${project.artifactId}であり、モジュールとサブモジュールのパターンは${project.parent.name}-${project.artifactId}です。

  • 会社任意の成果物任意モジュール1
  • company-any-artifact-any-module2-any-submodule1
  • company-any-artifact-any-module2-any-submodule2

project.build.finalNameのパターンは${project.name}-${project.version}です。

  • company-any-artifact-any-module1-1.0.jar
  • company-any-artifact-any-module2-any-submodule1-2.0.jar
  • company-any-artifact-any-module2-any-submodule2-3.0.war

しかし、これらのファイルを生成する代わりに、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.nameproject.build.fileNameをプロジェクトごとに手動で設定し、必要なパターンに従ってください。

重要な更新:

一部の回答は&{parent.name}を使用するように言っていますが、機能しません。賞金を伴う質問です。この質問に答える前に、Maven version 3.3.9でソリューションをテストすることを検討してください。

Mavenバージョン3.3.9

Edit-エラーが発生した段階で質問に詳細を追加すると、問題はprepare-packageフェーズですが、StackOverflowはプロジェクトのMavenライフサイクルのpackageフェーズで発生します。

18
Paulo

あなたの質問に対する厳密な答えは、_${project.parent.name}_がモデル補間プロセスの一部として解決されないことです。そして、コードの完全に異なる場所にStackOverflowErrorがあります。つまり、プロジェクトの最終的なJARをビルドするときです。

パート1:作成されたモデルが間違っている

ここで何が起こるかです。プロジェクトでMavenコマンドを起動する場合、最初に実行するアクションは、プロジェクトの効果的なモデルを作成することです。つまり、POMファイルの読み取り、アクティブ化されたプロファイルの推論、継承の適用、プロパティの補間の実行など、プロジェクトの最終的なMavenモデルを構築します。この作業は Maven Model Builder コンポーネントによって行われます。

モデルを構築するプロセスはかなり複雑で、多くのステップが2つのフェーズに分かれている可能性がありますが、ここで注目する部分は モデル補間 部分です。これは、Mavenがモデルで_${...}_によって示されるすべてのトークンを計算値に置き換えるときです。プロファイルが注入され、継承が実行された後に発生します。その時点では、MavenProjectオブジェクトで表されるMavenプロジェクトはまだ存在せず、Modelのみがビルドされています。そして、モデルからMavenプロジェクトの構築を開始できるのは、完全なモデルを作成した後です。

したがって、補間が行われるとき、それはPOMファイルに存在する情報に関してのみ理由であり、唯一の有効な値は モデル参照で言及された の値のみです。 (この置き換えは、ソースコードを確認したい場合、 StringSearchModelInterpolator クラスによって実行されます。)特に、モデルの_<parent>_要素がnotには、親モデルの名前が含まれます。 MavenのクラスModelは実際にはソース_.mdo_ファイルから Modello で生成され、そのソースは groupIdartifactIdversionおよび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_と見なすことを意味します。

パート2:奇妙な始まり

現在、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_という名前のプロジェクトの最終名を挿入します。
  • 親プロジェクトからの継承、および最上位のPOMプロジェクトでの_<finalName>_の宣言に感謝します。これは_<finalName>${project.name}-${project.version}</finalName>_を継承します。
  • Mavenは_${project.name}_に対して_any-submodule_を補間しようとしています。
  • パート1により、これは_${project.parent.name}-any-submodule_に解決されます。
  • Mavenは_${project.parent.name}_に対して_any-submodule_を補間しようとしています。これは正しく機能します。MavenProjectがビルドされ、プロジェクトインスタンスで getParent() が呼び出され、具体的なMaven親プロジェクトが返されます。そのため、_${project.parent.name}_は、実際には_any-module_である_${project.parent.name}-any-module_の名前を解決しようとします。
  • Mavenは_${project.parent.name}-any-module_、を補間しようとしていますが、それでも_any-submodule_プロジェクトインスタンスを使用しています。 PluginParameterExpressionEvaluatorの場合、トークンを評価するルート_"project"_は変更されていません。
  • Mavenは_${project.parent.name}_で_any-submodule_を補間しようとするようになりました。これもまた正しく機能し、_${project.parent.name}-any-module_を返します。
  • Mavenは_${project.parent.name}_で_any-submodule_を補間しようとするようになり、動作して_${project.parent.name}-any-module_を返すため、_${project.parent.name}_...を評価しようとします.

そして、ここで無限の再帰が発生していることがわかります。これにより、StackOverflowErrorが生成されます。これはPluginParameterExpressionEvaluatorのバグですか?これは不明確です。そもそも正しく置き換えられなかったモデル値が原因です。理論的には、常に現在のプロジェクトで作業するのではなく、_${project.parent}_を評価する特別なケースを処理して、この親プロジェクトで作業する新しいPluginParameterExpressionEvaluatorを作成できます。これについて強く感じた場合は、自由に作成してください JIRAの問題

パート3:サブモジュールなしで機能する理由

上記で述べたことで、このケースでそれが機能する理由を推測できます。 Maven Jarプラグインに挿入する必要があるため、最終名を評価するためにMavenが何を行う必要があるかを考えてみましょう。

  • _any-module_のJARプラグインは、_${project.parent.name}-any-module_という名前のプロジェクトの最終名を挿入します。
  • 親プロジェクトからの継承、および最上位のPOMプロジェクトでの_<finalName>_の宣言に感謝します。これは_<finalName>${project.name}-${project.version}</finalName>_を継承します。
  • Mavenは_${project.name}_に対して_any-module_を補間しようとしています。
  • これは、以前と同じように_${project.parent.name}-any-module_に解決されます。
  • Mavenは_${project.parent.name}_に対して_any-module_を補間しようとしています。以前と同じように、これは正しく動作します。MavenProjectがビルドされ、プロジェクトインスタンスで getParent() が呼び出され、具体的なMaven親プロジェクトが返されます。そのため、_${project.parent.name}_は、実際には_any-artifact_である_company-any-artifact_の名前を解決しようとします。
  • 補間は成功して停止します。

そして、エラーはありません。

9
Tunaki

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:エラーの実際の理由をより明確にしました(コメントを参照):

  • JarプラグインのfinalNameが評価されます:@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を(もう一度)返します。プロパティは常に現在のプロジェクトに対して解決されているので、サイクルが再び始まります。
  • StackOverflowErrorがスローされます。

これを解決する方法

残念ながらできません。

プロジェクトごとにname(およびartifactId)を明示的に指定する必要があります。回避策はありません。

次に、couldfinalNameに依存させます。しかし、私はそれに対して助言します( project.parent.nameとparent.nameの違いとpom.xml でのfinalNameの使用の違いを参照してください)

このように最終的な名前を変更する際の問題は、ローカルで作成されたアーティファクトとリポジトリ内のアーティファクトの名前が異なるため、ローカルではアーティファクトの名前はany-artifact-any-module-any-submodule.jarですが、リポジトリ内のアーティファクト名はany-submodule.jarのままです。

提案

  • 本当に細かく区別する必要がある場合は、代わりにアーティファクトIDを変更してください:<artifactId>artifact-anymodule-anysubmodule</artifactId>
  • 構造のレベルを区別するために、ショートネームにダッシュを使用しないでください。
  • ヒント:モジュールのpathanymoduleのままにすることができますが、モジュールの実際のArtifactIdである必要はありません!
  • ここでは、意図したとおりにnameを使用して人間が読めるようにします。これにより、視覚的に魅力的なものを検討できます(これはビルドログに表示される名前であるため)<name>Artifact :: AnyModule :: AnySubModule</name>
  • 実際には、非常に短いグルーヴィーなスクリプトを使用して名前エントリを自動的に作成するのは非常に簡単です。
  • また、artifactIdの命名を強制するための強制ルールを作成することもできます。
4
blackbuild

これは属性継承の問題です。
_${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.*}_を使うのが良い方法だと考えるべきです。

2
Javoslaw