Gradle Dependency DSL and Optional Dependencies


(thomas.glaeser) #1

In a perfect world, there should be no need to support something OSGi calls Optional Java Packages. Instead one could just assemble the optional Java packages into separate Java archives and then install/activate those archives only in environments that in fact make use of the optional functionality.

But no matter if the Java packages are declared as optional or delivered as a separate Java archive, it makes absolutely sense to install/activate only the requirements needed for a particular environment. Otherwise a whole set of dependencies, including transitive dependencies, would need to be resolved and processed even if never used.

An excellent approach to the very same problem is taken by Gentoo Linux by means of its [USE flags] (http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=2&chap=2) concept.

Therefore, would it be possible to add support of USE flags to the Gradle Dependency DSL?

Let’s assume that a provider declares the following dependencies for its module: dependencies {

compile group: ‘org.springframework’, name: ‘spring-core’, version: ‘2.5.0’

runtime group: ‘org.springframework’, name: ‘spring-aop’, version: ‘2.5.0’

runtime group: ‘org.hibernate’, name: ‘hibernate’, version: ‘3.0.5’ } Now, some of the consumers might not be interested in the ‘hibernate’ functionality and therefore would prefer that the provider declares its dependencies in the following way instead: configurations {

hibernateRuntime } dependencies {

compile group: ‘org.springframework’, name: ‘spring-core’, version: ‘2.5.0’

runtime group: ‘org.springframework’, name: ‘spring-aop’, version: ‘2.5.0’

hibernateRuntime group: ‘org.hibernate’, name: ‘hibernate’, version: ‘3.0.5’ } Other consumers instead might prefer to not pull in the ‘aop’ support and therefore would prefer that the provider declares its dependencies again differently: configurations {

aopRuntime } dependencies {

compile group: ‘org.springframework’, name: ‘spring-core’, version: ‘2.5.0’

aopRuntime group: ‘org.springframework’, name: ‘spring-aop’, version: ‘2.5.0’

runtime group: ‘org.hibernate’, name: ‘hibernate’, version: ‘3.0.5’ } However the provider insists that the default use case should include ‘aop’ support, but he is willing to explicitly mark this requirement: configurations {

runtime {

extendsFrom aopRuntime

} } dependencies {

compile group: ‘org.springframework’, name: ‘spring-core’, version: ‘2.5.0’

aopRuntime group: ‘org.springframework’, name: ‘spring-aop’, version: ‘2.5.0’

hibernateRuntime group: ‘org.hibernate’, name: ‘hibernate’, version: ‘3.0.5’ } The consumers depending on the optional ‘hibernate’ functionality would simply need to explicitly declare additional dependency for the optional functionality: dependencies {

compile group: ‘org.foo’, name: ‘foo-impl’, version: ‘latest.milestone’

compile group: ‘org.foo’, name: ‘foo-impl’, version: ‘latest.milestone’, configuration: ‘hibernateRuntime’ } The consumers that would like to exclude the ‘aop’ functionality would need to filter it out from its configuration declarations (I guess at the time being the exclude rules don’t accept a configuration notation): configurations {

compile.exclude module: ‘spring-aop’ } dependencies {

compile group: ‘org.foo’, name: ‘foo-impl’, version: ‘latest.milestone’ } So far, so good, this is all supported as of now and it would just be the providers responsibility to describe its module properly and document the different uses they support. ##### But wouldn’t it be great if one could declare this in just one dependency declaration instead of having each optional dependency from the same module added/filtered? Basically having the Gradle Dependency DSL adopting the concept of USE flags and adding support for additional property ‘use’ to its dependency map notation would significantly simplify the handling of optional dependencies: dependencies {

compile group: ‘org.foo’, name: ‘foo-impl’, version: ‘latest.milestone’, use: ‘+hibernate’ } dependencies {

compile group: ‘org.foo’, name: ‘foo-impl’, version: ‘latest.milestone’, use: ‘-aop’ } The use flags declared at the consumer side translate into ‘use’‘Compile’/‘use’‘Runtime’ configurations at the provider side that will automatically be added/subtracted from the providers ‘default’ configuration as specified by the use flags. dependencies {

compile group: ‘org.foo’, name: ‘foo-impl’, version: ‘latest.milestone’, use: ‘+hibernate, -aop’ } ##### As most of the use cases are relevant enterprise wide it would be good to register them via ‘init.d’.


(thomas.glaeser) #2

A poor men’s solution to the same problem would be adding support for resolving multiple remote configurations at once:

dependencies {
    compile group: 'org.foo', name: 'foo-impl', version: 'latest.milestone', configuration: 'runtime, hibernateRuntime'
}

This would be equivalent as supporting plus use flags only.