On 08/02/2012 04:58 AM, Anders Hammar wrote:
not have a dependency on some library in the plugin itself but rely on it being 
declared as a dependency in the Maven project where the plugin is bound. That 
made it
totally controllable by the project.

If the build-time code would not normally already be a dependency of the project - your main concern - then you could have the mojo configuration accept a parameter typed as a list of "dependencies". (org.apache.maven.model.Dependency[]?) These would then have to be resolved (transitively) against pluginRepositories, and used to construct a URL[] to pass to a URLClassLoader (possibly prepended to the project's regular dependencies). Thus the project could declare e.g.

<dependencies>
  <dependency>
    <groupId>some.framework</>
    <artifactId>the-api</>
  </>
  <dependency>
    <groupId>some.framework</>
    <artifactId>the-impl</>
    <scope>runtime</>
  </>
</>
<build>
  <plugins>
    <plugin>
      <groupId>some.framework</>
      <artifactId>the-plugin</>
      <configuration>
        <toolDependencies>
          <dependency>
            <groupId>some.framework</>
            <artifactId>the-build-tool</>
          </>
        </>
      </>
    </>
  </>
</>

Naturally you still need to be careful that a given version of the-plugin - specifically, that part of its code which will link against classes loaded by the URLClassLoader - is API-compatible with past, present, and foreseeable future versions of the-build-tool. If there are known breaking API changes, a single version of the plugin could also supply multiple adapters tuned to different version ranges of the-build-tool, or use reflection to try several method variants, or at least catch LinkageError and report the problem gracefully.

A mojo like this could be awkward to write from scratch; would be best to have an archetype for it. In particular, if you are using direct Java linkage between the-plugin code and the-build-tool (rather than, say, reflection), and the-plugin does not have a direct dependency on any version of the-build-tool (i.e. <toolDependencies> is mandatory and not just an optional selection of an alternative version) and/or supports multiple incompatible version ranges of the-build-tool, then to build the-plugin itself you need a multimodule project:

the-plugin-parent
  the-build-tool-abstraction (jar)
  the-build-tool-adapter-v1 (jar) -> the-build-tool-abstraction, the-build-tool 
@ [1.0.0,2)
  the-build-tool-adapter-v2 (jar) -> the-build-tool-abstraction, the-build-tool 
@ [2.0.0,3)
  the-plugin (maven-plugin) -> the-build-tool-abstraction

Here the-plugin resolves <toolDependencies> and determines which major version of the-build-tool is being requested ("1" or "2"). It then constructs a URLClassLoader parented to the plugin ClassLoader (or whatever loads classes from the-build-tool-abstraction) including everything from <toolDependencies> (resolved from pluginRepositories) plus the appropriate the-build-tool-adapter-v* (also from pluginRepositories), creates an instance of an interface defined in the-build-tool-abstraction and implemented in the-build-tool-adapter-v* (selected via java.util.ServiceLoader, Plexus @Component, ClassLoader.loadClass("hardcoded"), etc.), and casts to the-build-tool-abstraction interface which the plugin can directly "see". Then it calls methods on this instance to run the build tool.

Even if you are sure the-build-tool will be API-compatible it is not wise to mash everything into one project. While the-plugin could declare a <scope>provided</> dependency on the-build-tool, as the developer of the-plugin you would need to be careful to keep track of which src/main/java/**/*.java are permitted to refer to types in the-build-tool and which are not; furthermore, the URLClassLoader would then need to override loadClass to _not_ delegate loading of these classes to its parent (since then they would be loaded by the plugin class loader and fail to resolve against the-build-tool). Using a multimodule project as sketched above documents and enforces the runtime structure and means that the URLClassLoader can use normal parent delegation.


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to