我有一个使用 Ant 脚本构建的 Java 项目。我正在尝试将项目转换为 Maven。
其中一个任务生成一个名为 Version.java 的 Java 源文件,其中包含编译时间戳的静态字符串表示形式,如下所示:
package com.foo.bar;
public final class Version {
public static String VERSION="100301.1046";
}
Ant 任务非常简单:
<target name="version" depends="init" description="Create Version.java">
<echo file="src/${package.dir}/Version.java" message="package ${package.name};${line.separator}" />
<echo file="src/${package.dir}/Version.java" append="true" message="public final class Version {${line.separator}" />
<echo file="src/${package.dir}/Version.java"
append="true"
message=" public static String VERSION="${buildtime}";${line.separator}" />
<echo file="src/${package.dir}/Version.java" append="true" message="}${line.separator}" />
<echo message="BUILD ${buildtime}" />
</target>
是否可以使用generate-sources或其他一些简单方法在Maven中做类似的事情?
我认为这不是解决此类问题的好方法。
更好的方法是将版本信息放入
properties
文件中,该文件将由 Java 程序读取:
您的属性文件将包含以下行:
myapp.version=${project.version}
然后,在您的
pom.xml
中,指示该文件将被 Maven filtered :
<resources>
<resource>
<directory>the/directory/that/contains/your/properties/file</directory>
<filtering>true</filtering>
</resource>
</resources>
当 Maven 构建您的应用程序时,它将用它们的值替换所有
${...}
。默认情况下, ${project.version}
定义 pom.xml
的版本(即 <version>
标签的值)。
然后,在您的 Java 代码中,您只需要加载
properties
文件并检索 myApp.version
属性值。
请注意,您可以使用 Build Number 插件 设置比当前版本更“复杂”的内容(例如,如果您想将构建时间放入您的属性中)。
maven-replacer-plugin
:
pom 条目可能是:
<project>
...
<properties>
<version.template.file>src/main/java/com/stackoverflowVersion.java.template</version.template.file>
<version.file>src/main/java/com/stackoverflow/Version.java</version.file>
</properties>
...
<build>
<plugins>
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>maven-replacer-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<file>${version.template.file}</file>
<outputFile>${version.file}</outputFile>
<replacements>
<replacement>
<token>@buildnumber@</token>
<value>${svn.revision}</value>
</replacement>
<replacement>
<token>@buildtime@</token>
<value>${maven.build.timestamp}</value>
</replacement>
<replacement>
<token>@pomversion@</token>
<value>${project.version}</value>
</replacement>
</replacements>
</configuration>
</plugin>
</plugins>
</build>
...
</project>
Version.java.template 可能是:
package com.stackoverflow;
public final class Version {
public static final String build_number="@buildnumber@";
public static final String build_time="@buildtime@";
public static final String pomversion="@pomversion@";
}
这是一个老问题,但是还有另一个解决方案可以完美地做到“出色的工作”(在 Maven 意义上):Template Maven Plugin。
使用此插件会导致处理后的 Java 文件被放入
target/generated-sources
文件夹中,正如您所期望的那样。它将
generated-sources
下的文件夹添加到构建路径中。 您将不再错误签入已处理的文件。使用方法
首先将以下内容放在
src/main/java-templates/com/foo/bar/Version.java
下:
package com.foo.bar;
public final class Version {
public static final String VERSION = "${project.version}";
}
然后将以下内容添加到您的 POM 中:
<build>
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<id>filtering-java-templates</id>
<goals>
<goal>filter-sources</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
文件夹
target/generated-sources/java-templates
被Maven添加到构建路径中。
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<goals>
<goal>run</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<tasks>
<property name="src.dir" value="${project.build.sourceDirectory}" />
<property name="package.dir" value="com/foo/bar" />
<property name="package.name" value="com.foo.bar" />
<property name="buildtime" value="${maven.build.timestamp}" />
<echo file="${src.dir}/${package.dir}/Version.java" message="package ${package.name};${line.separator}" />
<echo file="${src.dir}/${package.dir}/Version.java" append="true" message="public final class Version {${line.separator}" />
<echo file="${src.dir}/${package.dir}/Version.java" append="true"
message=" public static String VERSION="${buildtime}";${line.separator}" />
<echo file="${src.dir}/${package.dir}/Version.java" append="true" message="}${line.separator}" />
<echo message="BUILD ${buildtime}" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
它似乎运行良好并生成了这个 Java 文件:
package com.foo.bar;
public final class Version {
public static String VERSION="100318.1211";
}
模板文件(VersionJava.template 放在 src/main/resources/version 中):
package ${ver.package.name};
public final class ${ver.class.name} {
public static String VERSION="${ver.buildtime}";
}
pom:
<properties>
...
<ver.package.dir>com/foo/bar${project.artifactId}</ver.package.dir>
<ver.package.name>com.foo.bar${project.artifactId}</ver.package.name>
<ver.class.name>Version</ver.class.name>
<ver.buildtime>${maven.build.timestamp}</ver.buildtime>
<ver.template.dir>src/main/resources/version</ver.template.dir>
<ver.template.file>VersionJava.template</ver.template.file>
</properties>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>version/*</exclude>
</excludes>
</resource>
<resource>
<directory>${ver.template.dir}</directory>
<includes>
<include>*.java</include>
</includes>
<filtering>true</filtering>
<targetPath>${basedir}/src/main/java/${ver.package.dir}</targetPath>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<configuration>
<tasks>
<copy file="${ver.template.dir}/${ver.template.file}" tofile="${ver.template.dir}/${ver.class.name}.java" />
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<phase>compile</phase>
<configuration>
<tasks>
<delete file="${ver.template.dir}/${ver.class.name}.java" />
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
这可能看起来有些过分,但它的用途非常广泛,也是我最喜欢它的地方 是我有可读格式的模板文件(而不是 pom 中的 echo 语句)。 这也允许我修改版本类而无需更改pom
的回答。这是一个简化版本,无需设置额外的属性。只是将项目的版本复制到 Version.java 中。 将
Version.java
放入
src/main/templates
:package thepackage;
public final class Version {
public static String VERSION="${project.version}";
}
指示maven替换Version.java中的token
<resources>
<resource>
<directory>src/main/templates</directory>
<includes>
<include>*.java</include>
</includes>
<filtering>true</filtering>
<targetPath>${project.build.directory}/generated-sources/java/thepackage</targetPath>
</resource>
</resources>
指示maven知道
generated-sources/java
作为构建路径(使用
build-helper-maven-plugin):
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/java/</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
最后让Eclipse m2e
注意新的构建路径
来实现的。
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<versionRange>[1.0,)</versionRange>
<goals>
<goal>parse-version</goal>
<goal>add-source</goal>
<goal>maven-version</goal>
<goal>add-resource</goal>
<goal>add-test-resource</goal>
<goal>add-test-source</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute>
<runOnConfiguration>true</runOnConfiguration>
<runOnIncremental>true</runOnIncremental>
</execute>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<versionRange>[1.0.0,)</versionRange>
<goals>
<goal>resources</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute>
<runOnConfiguration>true</runOnConfiguration>
<runOnIncremental>false</runOnIncremental>
</execute>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
thepackage
需要更换为您的包装:同时相应地调整
targetPath
。我发现在 targetpath
中设置路径比在 src/main/templates
中设置许多子文件夹更容易。 向 MANIFEST.MF 文件添加信息,然后用 Java 读取此 MANIFEST.MF 文件:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<Build-Time>${maven.build.timestamp}</Build-Time>
</manifestEntries>
</archive>
</configuration>
</plugin>
此配置生成以下 MANIFEST.MF 文件:
Manifest-Version: 1.0
Implementation-Title: MyApp
Implementation-Version: 2.11.0-SNAPSHOT
Built-By: niestroj
Specification-Title: MyApp
Implementation-Vendor-Id: com.mycompany
Build-Time: 2017-01-09 15:30
Created-By: Apache Maven 3.0.5
Build-Jdk: 1.8.0_40
Specification-Version: 2.11
后来我用 Java 读这个:
try {
Manifest manifest = new Manifest(getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF"));
Attributes attributes = manifest.getMainAttributes();
attributes.getValue("Implementation-Version");
attributes.getValue("Build-Time");
} catch (IOException ex) {
LOGGER.debug("Error reading manifest file information", ex);
}
/META-INF/maven/groupId/artifactId/pom.properties
;如果您不能或者无法提供您需要的所有内容,则可以滚动您自己的过滤文件) .
并且您是否想坚持使用实际的
Version
类,然后查看 Maven 用户列表上的
this thread,它正是为此提出了一个解决方案(基于您将绑定到的 antrun 插件)
generated-sources
阶段)。