Can a custom ResolutionStrategy be used to handle maven BOMs?


(Andres Almiray) #1

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


(Peter Niederwieser) #2

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.


(Andres Almiray) #3

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


(Peter Niederwieser) #4

It boils down to something like:

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

(Andres Almiray) #5

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:


(Peter Niederwieser) #6

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


(Andres Almiray) #7

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.


(Peter Niederwieser) #8

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


(Andres Almiray) #9

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?


(Peter Niederwieser) #10

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


(Andres Almiray) #11

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:


(Peter Niederwieser) #12

Glad you got it working.