Maven with an explicit finalName won't work properly

前端 未结 5 563
说谎
说谎 2021-01-17 10:46

1. Background

My maven project has a lot of modules and submodules with jars and wars and everything works. I also can dep

5条回答
  •  暖寄归人
    2021-01-17 11:29

    As I stated in my answer to Difference between project.parent.name and parent.name ans use of finalName in pom.xml

    Let's first look at the basics:

    as stated in POM Reference:

    finalName: This is the name of the bundled project when it is finally built (sans the file extension, for example: my-project-1.0.jar). It defaults to ${artifactId}-${version}.

    name: Projects tend to have conversational names, beyond the artifactId.

    So these two have different uses.

    • name is purely informational and mainly used for generated documentation and in the build logs. It is not inherited nor used anywhere else. It is a human readable String and can thus contain any character, i.e. spaces or characters not allowed in filenames. So, this would be valid: My Turbo Project on Speed!. Which is clearly at least a questionable file name for an artifact.

    • as stated above, finalName is the name of the generated artifact. It is inherited, so it should usually rely on properties. The only two really useful options are the default ${artifactId}-${version} and the versionless ${artifactId}. Everything else leads to confusion (such as a project named foo creating an artifact bar.jar). Actually, My turbo Project! would be valid, since this is a valid filename, but in reality, filenames like that tend to be rather unusable (try adressing a filename containing ! from a bash, for example)


    So, as to why the Stackoverflow happens:

    • name is not inherited
    • project.parent.name also is not evaluated during interpolation, since the name is one of the few properties which are completey invisible to the children
    • parent.name actually used to work in older Maven versions, but more due to a bug (also it is deprecated to access properties without the leading project).
    • a missing property is not interpolated, i.e. stays in the model as is
    • Therefore, in your effective pom for any-submodule, the value for finalName is (try it with mvn help:effective-pom) still: ${project.parent.name}-any-submodule

    So far so bad. Now comes the reason for the StackOverflow

    Maven has an addtional feature called late interpolation that evaluates values in plugin parameters when they are actually used. This allows a pluing to use properties that are not part of the model, but are generated by plugins earlier in the lifecycle (this allows, for instance plugins to contribute a git revision to the final name).

    So what happens is this:

    edit: made the actual reason for the error clearer (see comments):

    • The finalName for the jar plugin is evaluated: @Parameter( defaultValue = "${project.build.finalName}", readonly = true )
    • The PluginParameterExpressionEvaluator kicks in and tries to evaluate the final name (${project.parent.name}-any-submodule, which contains a property expression ${project.parent.name}.
    • The evaluator asks the model, which in turn returns the name of the parent project, which is: ${project.parent.name}-any-module.
    • So the evaluator tries to resolve this, which return ${project.parent.name}-any-module (again), since a property is always resolved against the current project, the cycle begins again.
    • A StackOverflowError is thrown.

    How to solve this

    Sadly, you can't.

    You need to explicitly specify name (as well as artifactId) for every project. There is no workaround.

    Then, you could let finalName rely on it. I would however advise against it (see my answer to Difference between project.parent.name and parent.name ans use of finalName in pom.xml)

    The problem in changing the final name that way is that the name of the locally build artifact and the one in the repository would differ, so locally your artifact is named any-artifact-any-module-any-submodule.jar, but the artifact name in your repository would be still any-submodule.jar

    Suggestion

    • If you really need to differentiate that fine, change the artifactId instead: artifact-anymodule-anysubmodule.
    • Don't use dashes for the shortname to differentiate between levels of your structure.
    • hint: the path of the module can be still anymodule, is does not need to be the actual artifactId of the module!
    • While we are at it: use the name for what it was intended, to be human readable, so you might consider something more visually appealling (since this is the name that appears in the build log): Artifact :: AnyModule :: AnySubModule.
    • It is actually very easy to simply create the name entries automatically using a very short groovy script.
    • You could also write an enforce rule to enforce the naming of the artifactIds

提交回复
热议问题