What is the way of excluding dependencies globally?

In the build I use dependency org.dbunit:dbunit in many places. Unfortunately lib authors added transitive dependency to the Oraccle & Postgre JDBC drivers.

I want to exclude them from the classpath, we use SQL Server & H2!

Per declaration exclusion requires repetitive code for each configuration × subproject:

https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/ModuleDependency.html#exclude-java.util.Map-

dependencies {
    implementation("org.dbunit:dbunit:${projDbunitVersion}") {
        exclude(group: "org.postgresql")
        exclude(group: "com.oracle.database.jdbc")
    }
}

To make the settings global earlier I put to root build.gradle:

https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/Configuration.html#exclude-java.util.Map-

subprojects {
    configurations.all {
        exclude(group: "org.postgresql")
        exclude(group: "com.oracle.database.jdbc")
    }
}

Today I leaned about settings.gradle block dependencyResolutionManagement:

dependencyResolutionManagement {
    components {
        all {
            allVariants {
                withDependencies {
                    removeAll {
                        // org.dbunit:dbunit strangely pulls PostgreSQL and Oracle JDBC drivers.
                        it.group in [ "org.postgresql", "com.oracle.database.jdbc" ]
                    }
                }
            }
        }
    }
}

The latest syntax looks alien.

What is idiomatic way to exclude or replace / configure dependencies globally for all submodules? Should I investigate resolutionStrategy?

What is the difference between withDependencies & resolutionStrategy?

The subprojects { ... } way is evil, as it does cross-project configuration.

Your last one, that uses a component metadata rules almost is the idiomatic way to do what you want, not what you asked for.

You should not exclude the dependency, and with the component metadata rule you do not exclude somehting, but you fix the wrong metadata of dependencies.
You can read more details about it at Fixing metadata with component metadata rules.
I would probably do it more targeted, component metadata rules are a scalpel, not a hammer.
So for example replace all { by withModule("org.dbunit:dbunit") { to fix the incorrect metadata of exactly that module.

@Vampire I don’t know the way I could implement your idea:

You should not exclude the dependency, and with the component metadata rule you do not exclude somehting, but you fix the wrong metadata of dependencies.

I’m able to target module with components.withModule("org.dbunit:dbunit") syntax but for removal I came only with allVariants.withDependencies.removeAll (this time I converted to Kotlin as I was tired of logger.lifecycle in Groovy):

dependencyResolutionManagement {
    components {
        withModule("org.dbunit:dbunit") {
            allVariants {
                withDependencies {
                    removeAll {
                        it.group in arrayOf("org.postgresql", "com.oracle.database.jdbc")
                    }
                }
            }
        }
    }
}

withDependencies with logger.lyfecycle("deps: {}", this) listed only 3 deps with two offending and I’m not sure if I can manipulate withDependencies.this directly with removeAll.

Also I have difficulty understanding allVariants. Following:

allVariants { logger.lifecycle("var: {}", this.attributes) }

printed:

var: {org.gradle.status=release}

Like I have only one variant (as I didn’t configure this new Gradle feature). Seems with different variants you might have different dependency graph… But I don’t understand how metadata could change based on variant… I thought it is static in Maven/Ivy/etc repository…

Making the way through Gralde abstractions is quite difficult ((

@Vampire I don’t know the way I could implement your idea:

Why?
You did exactly what I suggested, removing all by withModule, so :ok_hand:.

Like I have only one variant

It’s not about you only having one variant, it is about org.dbunit:dbunit only having one variant.
But even that is most probably not correct.
Even things that do not have explicit variants (e.g. in published Gradle module metadata) have some variants derived from the existing metadata like POM or Ivy file.
But the content of allVariants { ... } is afair just evaluated for the variants that are actually requested, so you only get one line printed.

Seems with different variants you might have different dependency graph

Yes, different variants could have different dependencies.

But I don’t understand how metadata could change based on variant… I thought it is static in Maven/Ivy/etc repository…

It is, variants are part of the metadata.
In Gradle Module Metadata they are explicit, for pure POM or Ivy dependencies some variants are derived from the information available as documented.