How to filter resource in Maven, replacing with a

2019-01-26 14:52发布

问题:

I'm trying to build a jar that has an xml file as a resource. I'd like to apply a filter to that xml to insert the name of a dependency into the xml. The filtering is working, because I was able to drop in ${project.build.finalName} and get it replaced. I found one hint that the property I'm looking for might be

${project.dependencies[0].artifactId}

but that doesn't seem to work. I'm looking to replace

<fileName>${project.dependencies[0].artifactId}</fileName>

with

<fileName>OtherLibrary</fileName>

Is that possible?

xml, which is in src/main/resources:

<somenode>
  <fileName>${project.dependencies[0].artifactId}</fileName>
</somenode>

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
<groupId>com.foo</groupId>
<artifactId>Thing</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Thing</name>
<url>http://maven.apache.org</url>
<build>
    <resources>
        <resource>
            <directory>${basedir}/src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>
<dependencies>
    <dependency>
        <groupId>com.pts</groupId>
        <artifactId>OtherLibrary</artifactId>
        <version>1.0-SNAPSHOT</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>
</project>

回答1:

Damn, you're right, this property doesn't get replaced during the filtering of resources. That's weird and it sounds like a bug in the Maven Resources Plugin because this property is correctly interpolated during the process-resources phase as I'll demonstrate in the workaround I'm suggesting below (based on the maven-antrun-plugin and the replace task).

First, add the following to your POM:

  <plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
      <execution>
        <phase>process-resources</phase>
        <configuration>
          <tasks>
            <echo>${project.dependencies[0].artifactId}</echo><!-- I'm a test -->
            <replace file="${project.build.outputDirectory}/myxmlfile.xml" 
                     token="@@@" value="${project.dependencies[0].artifactId}"/> 
          </tasks>
        </configuration>
        <goals>
          <goal>run</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

Then, update your XML file into:

<somenode>
  <fileName>@@@</fileName>
</somenode>

With these changes, running mvn process-resources would produce the following result:

$ cat target/classes/myxmlfile.xml 
<somenode>
  <fileName>OtherLibrary</fileName>
</somenode>

Which proves the property is interpolated (but not set during maven filtering of resources)1. And if you need to filter more than one file, the replace task can take a fileset. Adapt it to suit your needs.

1 Actually, it would be nice to create a new Jira for this bug in the Maven 2.x Resources Plugin. I've created MRESOURCES-118.



回答2:

The indexed properties will only be available inside plugin configuration due to the way Maven interpolates the POM - so it is available to antrun's replace task, but not the filtering.

However, accessing dependencies by index is not very robust - it is susceptible to changes in the parent. You might instead use the following in pom.xml:

<properties>
  <fileName>some-name</fileName>
</properties>
...
<dependency>
  <groupId>your.group.id</groupId>
  <artifactId>${fileName}</artifactId>
  ...
</dependency>

You can then continue to filter using the property name:

<somenode>
  <fileName>${fileName}</fileName>
</somenode>