动态maven artifactId

Posted

技术标签:

【中文标题】动态maven artifactId【英文标题】:Dynamic maven artifactId 【发布时间】:2016-05-03 13:07:26 【问题描述】:

POM 是否可以声明(或至少发布)包含系统属性的artifactId?我的意思是实际项目的 artifactId,而不是依赖项。

我正在使用 maven 构建一个 scala 项目,因此,为了允许为不同的 scala 版本发布项目,我想在 pom.xml 中声明:

<artifactId>myproject_$scalaBinaryVersion</artifactId>

然而 maven 3.3.抱怨

[WARNING] 'artifactId' 包含一个表达式,但应该是一个常量

既然我希望这个项目能够与 sbt 互操作,那么发布以 scala 二进制版本为后缀的工件的最佳方式是什么?

【问题讨论】:

使用分类器而不是更改 artifactId 怎么样? 不幸的是,由于传递依赖无法区分,分类器无法工作 【参考方案1】:

这样做的Maven 方式是使用classifiers。来自官方文档的示例与您的情况完全匹配(对于不同的 Java 版本,但您可以用 Scala 替换 Java):

分类器允许区分从同一个 POM 构建但内容不同的工件。它是一些可选且任意的字符串——如果存在的话——被附加到工件名称之后,紧跟在版本号之后。 作为这个元素的动机,例如,考虑一个项目,它提供了一个针对 JRE 1.5 的工件,但同时也提供了一个仍然支持 JRE 1.4 的工件。第一个工件可以配备分类器 jdk15,第二个工件配备 jdk14,以便客户端可以选择使用哪一个。

您可以按如下方式配置您的 POM:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.5</version>
            <executions>
                <execution>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                    <configuration>
                        <classifier>$scalaBinaryVersion</classifier>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

注意:我们正在添加 Maven Jar 插件的额外执行,因此项目将创建两个 jar,一个普通的 + 一个带有指定(动态)分类器的附加。

然后Maven会自动将分类jar和普通jar一起发布(因为它会自动附加到构建中)。然后,您可以将其作为另一个项目中的进一步 Maven 依赖项导入,将其分类器指定为 Maven GAV(在本例中为 GAVC)的一部分:

<dependency>
    <groupId>your.group.id</groupId>
    <artifactId>your.constant.artifact.id</artifactId>
    <version>your.version</version>
    <classifier>your.dynamic.classifier</classifier>
</dependency>

如果您只想构建分类的一个并且没有标准(未使用)的jar,您可以跳过创建普通jar,如下所示:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.5</version>
            <executions>
                <execution>
                    <id>default-jar</id>
                    <phase>none</phase>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                </execution>
                <execution>
                    <id>scala-version-jar</id>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                    <configuration>
                        <classifier>$scalaBinaryVersion</classifier>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

注意:我们只是覆盖 Jar 插件的默认执行并将其绑定到不存在的阶段。因此 Maven 只会生成分类的 Jar。然后安装插件将只安装分类的。


更新:如何使用动态依赖项安装动态 artifactId

如果不同的动态版本需要不同的传递依赖,那么分类器确实不适合。 然而,可以实现具有动态依赖关系(以及因此动态传递依赖关系)的动态 artifactId。以下是我使用(并成功测试)的方法:

作为偏好,我隔离了配置文件中的动态行为,但您显然可以将其移回默认构建(或默认激活配置文件)。

首先,让我们在 pom 中定义需要动态版本的依赖项,因此通过以下属性:

<properties>
    <scalaBinaryVersion>scalaversion</scalaBinaryVersion>
    <dependency.version>4.11</dependency.version>
</properties>

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>$dependency.version</version>
    </dependency>
</dependencies>

注意:举个例子,在这种情况下,我使用 Junit 作为依赖项,而不是在 test 范围内,因为我希望它作为 compile 依赖项(同样,仅用于此示例)。

然后让我们为我们的动态行为定义一个配置文件:

<profiles>
    <profile>
        <id>build-scala-version</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>2.5</version>
                    <configuration>
                        <finalName>$project.artifactId_$scalaBinaryVersion-$project.version</finalName>
                    </configuration>
                </plugin>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>2.7</version>
                    <executions>
                        <execution>
                            <id>copy-pom</id>
                            <phase>generate-resources</phase>
                            <goals>
                                <goal>copy-resources</goal>
                            </goals>
                            <configuration>
                                <outputDirectory>$project.build.directory/$scalaBinaryVersion</outputDirectory>
                                <resources>
                                    <resource>
                                        <directory>$basedir</directory>
                                        <includes>
                                            <include>pom.xml</include>
                                        </includes>
                                        <filtering>true</filtering>
                                    </resource>
                                </resources>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>

                <plugin>
                    <groupId>com.google.code.maven-replacer-plugin</groupId>
                    <artifactId>replacer</artifactId>
                    <version>1.5.1</version>
                    <executions>
                        <execution>
                            <id>replace-artifactid</id>
                            <phase>prepare-package</phase>
                            <goals>
                                <goal>replace</goal>
                            </goals>
                            <configuration>
                                <file>target/$scalaBinaryVersion/pom.xml</file>
                                <token>&lt;artifactId&gt;$project.artifactId&lt;/artifactId&gt;</token>
                                <!-- Replace to -->
                                <value>&lt;artifactId&gt;$project.artifactId_$scalaBinaryVersion&lt;/artifactId&gt;</value>
                                <outputDir>target\$scalaBinaryVersion\replacer</outputDir>
                                <outputFile>pom.xml</outputFile>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                    <executions>
                        <execution>
                            <id>default-install</id>
                            <configuration>
                                <skip>true</skip>
                            </configuration>
                        </execution>
                        <execution>
                            <id>install-scala-version</id>
                            <phase>install</phase>
                            <goals>
                                <goal>install-file</goal>
                            </goals>
                            <configuration>
                                <groupId>$project.groupId</groupId>
                                <artifactId>$project.artifactId_$scalaBinaryVersion</artifactId>
                                <version>$project.version</version>
                                <packaging>$project.packaging</packaging>
                                <file>$project.build.directory/$project.artifactId_$scalaBinaryVersion-$project.version.jar</file>
                                <pomFile>$project.build.directory/$scalaBinaryVersion/replacer/pom.xml</pomFile>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

请注意,配置文件正在自定义并提供以下内容:

根据运行时(也称为动态)值,将最终 Jar 名称更改为动态名称$project.artifactId_scalaBinaryVersion-$project.version 通过 Maven 资源插件和copying 过滤现有的 pom 文件到目录target\$scalaBinaryVersion。复制的 pom 将具有与动态版本的依赖关系,因为资源插件将替换它们。但是,它还没有动态 artifactId。 完成动态 pom 文件。 Replacer 插件将用动态值替换 artifactId XML 元素(在 target 文件夹上工作,因此所有内容都在临时文件中) 跳过默认安装的生成 使用动态 pom 文件(过滤、复制和替换的文件)执行自定义 install-file installation,提供动态依赖项(以及动态传递依赖项)和动态 artifactId

因此,执行以下 maven 调用:

mvn clean install -Pbuild-scala-version -DscalaBinaryVersion=hello -Ddependency.version=4.4

Maven 将有效地在本地缓存中为动态 artifactId、动态依赖版本和动态 pom 安装新的工件。 注意:如果相关依赖版本和动态 scala 版本相同,那么您可以保存一个参数并使调用更短且更一致。

【讨论】:

感谢您的回答,但是无法使用分类器,因为传递依赖会存在问题,并且 sbt 依赖于 artifactId 中存在的二进制版本 分类器有哪些问题? 假设以下依赖项:- project_2.10 -> lib_2.10 -> onlyscala2.10 和 - project_2.11 -> lib_2.11 -> onlyscala2.11 据我所知,分类器可以t有不同的依赖关系 @JakobOdersky 确实,你是对的,在这种情况下传递依赖将是一个问题。我用不同的方法在底部更新了我的答案:它在我的本地测试中运行良好,我得到了具有动态依赖项和传递依赖项的动态 artifactId。这是一个循序渐进的方法,但解决方案效果很好。 我遵循了你的第二种方法,虽然它适用于mvn install ...,但我还没有弄清楚如何使用 maven-release-plugin 发布交叉编译的库。有什么提示吗?【参考方案2】:

如果您为此使用 maven,我将使用带有 maven helper plugin 的 multi pom 进行 saggest,因此 artifactId 在每个模块中都是恒定的。

【讨论】:

【参考方案3】:

我们遵循此处建议的基于属性(通过配置文件)的方法:scala-maven-plugin FAQ

<artifactId>something_$scala.compat.version</artifactId>

<properties>
 <scala.compat.version>2.12</scala.compat.version>
</properties>

maven 仍然会发出警告(有充分的理由),但在flatten-maven-plugin 的帮助下,我们构建/安装了替换变量的 pom。

【讨论】:

我们已经为每个 scala 兼容版本创建了一个 pom 文件,该文件有一个静态 artifactId(并配置了 scala 编译器插件以在不同的文件夹中查找它的源代码) 不好:[WARNING] 'artifactId' 包含一个表达式,但应该是一个常量。

以上是关于动态maven artifactId的主要内容,如果未能解决你的问题,请参考以下文章

生成资源文件时候,可以动态替换为maven属性

Jenkins+maven动态打包配置文件

Eclipse创建一个 Maven 动态web项目

eclipse 创建maven 项目 动态web工程完整示例

eclipse 创建maven 项目 动态web工程完整示例

动态maven artifactId