javamavenmaven-resources-pluginplexus

Custom MavenResourcesFiltering hard to implement?


I’d like to write a custom resource filter for some source files, in order to prepend a line

// @sourceURL=<path-to-file> 

during resource filtering, where <path-to-file> is the path of the file relative to ${project.basedir}.

I followed Maven Custom resources filters documentation, saying that I need to write a custom implementation of the interface MavenResourcesFiltering.

After looking at org.apache.maven.shared.filtering.DefaultMavenResourcesFiltering I figured that writing a MavenResourcesFiltering implementation from scratch isn’t trivial. So I was looking for ways to extend from DefaultMavenResourcesFiltering, and found that I’ll need to supply it with a custom MavenFileFilter that does the actual prepending of lines.

Now it occurs to me that there is no way to do this, other than copying the whole sourcecode of DefaultMavenResourcesFiltering, in order to be able to redefine its @Requirement annotation for a MavenFileFilter:

@Requirement
private MavenFileFilter mavenFileFilter;

Probably there are ways to achieve my goals by configuration of the Plexus DI container, perhaps by means of a Plexus Component Descriptor. Alas that's a bit exotic, maybe somebody knows of a good example for a similar problem?


Solution

  • Probably there are ways to achieve my goals by configuration of the Plexus DI container, perhaps by means of a Plexus Component Descriptor

    Yes, there is a way. You need to override the "default" MavenFileFilter component that is used by the DefaultMavenResourcesFiltering, and provide your own. This is easily done: just create your own Plexus Component for the MavenFileFilter role and overriding the "default" hint, and add it as a dependency of the Resources Plugin. Since the classes directly present under the plugin's dependencies are loaded first, they will override the default ones.

    The set-up is the following. Create a new Maven project having the following POM:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>my.groupId</groupId>
      <artifactId>my-file-filter</artifactId>
      <version>0.0.1</version>
      <dependencies>
        <dependency>
          <groupId>org.apache.maven.shared</groupId>
          <artifactId>maven-filtering</artifactId>
          <version>3.1.1</version>
        </dependency>
      </dependencies>
      <build>
        <plugins>
          <plugin>
            <groupId>org.codehaus.plexus</groupId>
            <artifactId>plexus-component-metadata</artifactId>
            <version>1.6</version>
            <executions>
              <execution>
                <goals>
                  <goal>generate-metadata</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </project>
    

    This has a dependency on the Maven Filtering shared component, and declares the plexus-component-metadata plugin in order to generate the Plexus component.xml automatically (so that our classes are correctly registered as Plexus components).

    Then, the custom file filter is simple: it is possible to inherit from the default one, which is DefaultMavenFileFilter:

    @Component(role = MavenFileFilter.class, hint = "default")
    public class MyMavenFileFilter extends DefaultMavenFileFilter {
    
        public void copyFile(File from, File to, boolean filtering, List<FileUtils.FilterWrapper> filterWrappers, String encoding, boolean overwrite) throws MavenFilteringException {
            super.copyFile(from, to, filtering, filterWrappers, encoding, overwrite);
            // your logic of modifying the "to" file here
        }
    
    }
    

    This simply overrides the copyFile method that all the other method end up calling, makes sure the default behaviour is still happening by calling the super method, and then doing your custom code. In this part, you can process the to File and prepent the line you want in it.

    Once this Maven project is installed with mvn clean install, you can add it as a depenndecy to the Resources Plugin with:

    <plugin>
      <artifactId>maven-resources-plugin</artifactId>
      <version>3.0.1</version>
      <dependencies>
        <dependency>
          <groupId>my.groupId</groupId>
          <artifactId>my-file-filter</artifactId>
          <version>0.0.1</version>
        </dependency>
      </dependencies>
    </plugin>
    

    and it is your custom file filter that will be injected inside DefaultMavenResourcesFiltering.