Can a custom ResolutionStrategy be used to handle maven BOMs?

Recently discovered that spring-boot uses a custom ResolutionStrategy to force a particular version for all of the spring-boot dependencies

https://github.com/spring-projects/spring-boot/blob/master/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/resolve/SpringBootResolutionStrategy.java

I wonder if this idea can be reused to handle maven BOMs. My use case involves multiple artifacts related to a Griffon plugin. Take for example the scaffolding plugin, it defines (at least) the following artifacts

  • griffon-scaffolding

  • griffon-scaffolding-groovy

  • griffon-scaffolding-groovy-compile

  • griffon-scaffolding-swing

  • griffon-scaffolding-javafx

Without a custom resolution strategy you must define all JARs according to your setup, for example using Swing and Groovy you’ll need

dependencies {
    compileOnly 'org.codehaus:griffon.plugins:griffon-scaffolding-groovy-compile:1.0.0'
    compile 'org.codehaus:griffon.plugins:griffon-scaffolding:1.0.0'
    compile 'org.codehaus:griffon.plugins:griffon-scaffolding-groovy:1.0.0'
    compile 'org.codehaus:griffon.plugins:griffon-scaffolding-swing:1.0.0'
    compile 'org.codehaus:griffon:griffon-swing:2.0.0'
    compile 'org.codehaus:griffon:griffon-groovy:2.0.0'
}

With a custom resolution strategy the dependencies block could be reduced to

dependencies {
    compile 'org.codehaus:griffon.plugins:griffon-scaffolding-plugin:1.0.0'
    compile 'org.codehaus:griffon:griffon-swing:2.0.0'
    compile 'org.codehaus:griffon:griffon-groovy:2.0.0'
}

Can the following operations be performed by such strategy?

  • remove the ‘griffon-scaffolding-plugin’ dependency from the ‘compile’ configuration

  • query/download/cache ‘griffon-scaffolding-plugin.pom’ (which is a BOM)

  • parse the BOM and include the dependencies it declares in the right configurations (compile, compileOnly, etc)

TIA Andres

It should be possible to perform these operations in ‘configuration.incoming.beforeResolve {}’. One question is how ‘griffon-scaffolding-plugin’ can be identified as a BOM. Perhaps you could require the dependency declaration to end in ‘@pom’, remove it from the original configuration, resolve it using a ‘configurations.detachedConfiguration()’, parse the BOM, then add the found dependencies to the original configuration (all in ‘beforeResolve’). This is just a first idea, but hopefully it will get you started.

Thanks Peter :slight_smile:

A generic solution (not griffon related) would require a BOM to be mark with ‘@pom’, but in this case I not only need to identify the BOM but also move dependencies to Griffon specific configurations (such as compileOnly and testCompileOnly), thus I think it’s OK for this plugin to assume a naming convention: anything that matches ‘griffon-*-plugin’ will be treated as a BOM.

Could you provide more details on the gradle API used to query and download poms? In theory the BOM should be downloaded once and placed in the cache. I wouldn’t want this custom BOM resolution to always hit the network (unless it’s a snapshot of course :wink:

Cheers, Andres

It boils down to something like:

def pomFile = configurations.detachedConfiguration(
    dependencies.create("org.codehaus:griffon.plugins:griffon-scaffolding-plugin:1.0.0@pom")
).singleFile()

Is there a way to force a configuration to be resolved before others? I thought the following would be possible

dependencies {
    griffonPlugin 'org.codehaus.griffon.plugins:griffon-datasource-plugin:1.0.0'
      compile "org.codehaus.griffon:griffon-swing:$griffonVersion"
    compile "org.codehaus.griffon:griffon-guice:$griffonVersion"
}

However ‘griffonPlugin’ is resolved after ‘compile’ so there’s no chance for the former to change the latter. The only way I can think of at the moment is to change the name of ‘griffonPlugin’ to be alphabetical lower than ‘compile’, as in ‘agriffonPlugin’ :frowning:

A configuration is resolved when its files are first requested. Declaration order and naming doesn’t matter.

OK, but then again, is there a way to process a configuration before any other configuration is resolved? So far I’m able to pre process ‘griffonPlugin’ with beforeResolve but I’m unable to update ‘compile’ because it has been resolved already.

Why not resolve ‘griffonPlugin’ in ‘compile.beforeResolve’? And why did you change your plans and are now using a ‘griffonPlugin’ configuration?

Because even if I use ‘compile’ as in the original message I still need to update ‘compileOnly’, 'testCompileOnly, ‘test’, and ‘runtime’ given whatever details appear in the BOM. Adding a non-visible configuration such as 'griffonPlugin’shouldn’t matter, does it?

The point still remains if it’s 'compile’or not, other configurations must be updated but they may have been resolved already by the time the BOM is parsed.

Another option could be registering a ‘beforeResolve’ for all target configurations, poitining to the same Action. The action would know which configuration can be updated and affect that one alone. This however has the drawback of parsing the BOM many times unless the results of the first parse can be stored somewhere in memory. WDYT?

Last paragraph seems like the way to go. You can store the parse results in a local variable.

Yup. Got it to work. For anyone interested in a rough cut of this feature here’s the link for reference

https://github.com/griffon/griffon/commit/359608f8429381e615a8639dd74f0d3a59e653e1

Thanks a lot for your help Peter :slight_smile:

Glad you got it working.