The page explains how to apply "Maven Plugin SPI" pattern.

Basic situation is following: you have a Maven Plugin, that you want to make extensible in some way, without making the plugin itself an extension. 

Example: remember Maven Deploy Plugin early "deploy at end" solution, when it required to make plugin an extension for a feature to work? It just introduced a ton of confusion to users. Basically, goal is to modify (or extend) plugin behavior in orthogonal way.

Maven Plugins and Mojos are envisioned to be simple, do one thing, and do it well (aka "U*IX philosophy). This works well in many cases, but there are situations when you want to introduce completely different behavior for some reason to some plugins. 

How can a Plugin implement SPI pattern?

The pattern in short is following: provide some SPI component interfaces in a separate Maven Plugin SPI artifact. Make the plugin depend on this SPI artifact and let plugin provide "default" implementations for SPI. Basically, you introduce an indirection, where the plugin contained SPI implementations contains the factored out plugin original code (the one that is to be altered or extended).

At "everyday" runtime, when the plugin runs following happens:

maven-plugin-spi

How to provide alternate SPI implementation?

By using proper Maven extension mechanism. The Maven Plugin SPI Extension should make the SPI artifact "exported artifact". This will prevent Plugin SPI to be resolved (for given plugin), instead Maven Core will provide the SPI artifact and Java packages (interfaces) from it to Maven Plugin, making sure classloading is correct.

maven-plugin-spi

This way the Maven Plugin SPI Extension can also provide SPI interface component implementations, and make them available to the Maven Plugin itself, without making any change on Plugin itself (like making it an extension or alike).

Possible problems

Given we deal now with two distinct versions of Maven Plugin SPI artifact (one Maven Plugin depends on, and one Maven Plugin SPI provides), the problem of "binary compatibility" arises. We can address these in multiple ways:

  • The Plugin SPI artifact should be really "rarely changing" (rarely released) and protected in most complete way (for example using japicmp at build time) against binary breakages. 
  • The versioning of artifact could follow strict schema, ensuring that all same-major releases are binary compatible.
  • SPI packages could incorporate major version as well, hence major version jumps would switch Java package, causing "early breakage" in case of wrong combination (Plugin using X major SPI version while SPI Extension providing Y major SPI version where X!=Y). This is needed as core provided artifacts are GA keyed, so version is omitted.

TBD

  • No labels