views:

1235

answers:

2

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"&gt;
  <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&lt;/url&gt;
<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>
+2  A: 

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.

Pascal Thivent
the interpolation and filtering do not use the same algorithm, so the filtering is only going to have a subset of the expressions
Brett Porter
@Brett Thanks for the explanation.
Pascal Thivent
Thanks for adding the bug report, and for the workaround.
Jim
+1  A: 

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>
Brett Porter
Actually, I did try what you are suggesting in the first solution when I was writing my answer (and mentioned it in in http://jira.codehaus.org/browse/MRESOURCES-118) but this didn't work, you'll get `<fileName>${project.dependencies[0].artifactId}</fileName>` in the filtered resource. But the second solution is definitely a good one.
Pascal Thivent
you're right, sorry about that. The interpolation mechanisms are something that has undergone quite a bit of change between Maven 2.0.x, 2.2.x, and 3.0. I believe this expression will only be available inside plugin configuration in most versions of Maven, so it is best not to rely on it at all.
Brett Porter
I should point out that the reason I'm looking for this is what I would guess is a unique situation/edge case where I need to add non EJB jar into my persistence.xml. And because the ear plugin doesn't have a way to specify the naming convention for jars in the lib folder, I've gone down this path. The war plugin has a nice way to make jars follow a naming pattern that I wish the ear plugin had. See http://jira.codehaus.org/browse/MEAR-98 for example.Eventually I'm going to code the non-ejb jar out of existence. It's just a jar I inherited and am working to integrate.
Jim