spring-gradle-plugins / dependency-management-plugin

A Gradle plugin that provides Maven-like dependency management functionality
690 stars 88 forks source link

When importing a bom, allow a bom that it imports to be excluded #317

Open voduku opened 2 years ago

voduku commented 2 years ago

I would like to know how to exclude a specific dependency from spring boot dependencies in gradle. I am asking this because due to internal restriction and licensing, I can't pull com.oracle.database.jdbc:ojdbc-bom. Despite trying all exclusion recommendation out there, including instruction from spring boot gradle plugin page, none of them seems to be able to alter detachedConfiguration. I get this error no matter what.

Execution failed for task ':compileJava'.
> Could not resolve all files for configuration ':detachedConfiguration24'.
   > Could not find com.oracle.database.jdbc:ojdbc-bom:21.3.0.0.

My build.gradle:


plugins {
    id 'org.springframework.boot' version '2.6.2'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = ''
version = '1.0.0'
sourceCompatibility = '17'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

configurations.all {
    exclude group: 'com.oracle.database.jdbc', module: 'ojdbc-bom'
}

repositories {
    ... // some internal repo that mimic mavenCentral() but with licensing restriction
}

bootJar {
    enabled = false
}

jar {
    enabled = true
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
    implementation 'io.r2dbc:r2dbc-postgresql'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
}

test {
    useJUnitPlatform()
}
jonathanq commented 7 months ago

I've run into the same issue. The inclusion of the Oracle BOM which has a commercial license (not open source) is making it difficult to use any springboot project internally.

Is there a way to exclude it? Or stop referencing it by default since it's not an open source license?

wilkinsona commented 7 months ago

As things stand, if you want greater control over this I would recommend using Gradle's built-in platform support instead of the dependency management plugin. You should be able to exclude the Oracle Database bom when you declare the platform dependency on spring-boot-dependencies.

jonathanq commented 6 months ago

I have't been able to find any way to add an exclusion that works. I will open a ticket with the spring-boot-project and see if they are willing to separate out the oracle dependency (https://github.com/spring-projects/spring-boot/blob/5600a02834d054ed86d2353a30d3c9f90acc7fd8/spring-boot-project/spring-boot-dependencies/build.gradle#L1382-L1392) since it's not licensed as open-source.

wilkinsona commented 6 months ago

This should work with Gradle's platform support:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.3'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) {
        exclude(group: "com.oracle.database.jdbc")
    }
    implementation("com.oracle.database.jdbc:ojdbc11")
}

Due to the exclusion on the platform dependency, the runtime classpath will fail to resolve as there's no version available for com.oracle.database.jdbc:ojdbc11:

 gradle dependencies --configuration runtimeClasspath        

> Task :dependencies

------------------------------------------------------------
Root project 'exclude-oracle-bom'
------------------------------------------------------------

runtimeClasspath - Runtime classpath of source set 'main'.
+--- org.springframework.boot:spring-boot-dependencies:3.2.3
\--- com.oracle.database.jdbc:ojdbc11 FAILED

I've verified this as best I can by preventing com.oracle.database.jdbc downloads from Maven Central:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.3'
}

repositories {
    mavenCentral() {
        content {
            excludeGroup("com.oracle.database.jdbc")
        }
    }
}

dependencies {
    implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
    implementation("com.oracle.database.jdbc:ojdbc11")
}

This shows a failure for Boot's bom as well as the ojdbc11 dependency:

$ gradle dependencies --refresh-dependencies --configuration runtimeClasspath                    

> Task :dependencies

------------------------------------------------------------
Root project 'exclude-oracle-bom'
------------------------------------------------------------

runtimeClasspath - Runtime classpath of source set 'main'.
+--- org.springframework.boot:spring-boot-dependencies:3.2.3 -> 3.2.3 FAILED
\--- com.oracle.database.jdbc:ojdbc11 FAILED

This is to be expected as the complete state of spring-boot-dependencies cannot be resolved.

jonathanq commented 6 months ago

I tried that first example:

dependencies {
    implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) {
        exclude(group: "com.oracle.database.jdbc")
    }
}

However in Gradle 8.6 (I'm using a Kotlin build file) - it doesn't compile. I tried removing the group: and it still doesn't work. What version of Gradle were you trying that on?

wilkinsona commented 6 months ago

My example's for the Groovy DSL. The equivalent in the Kotlin DSL, working around what appears to be a Gradle Kotlin DSL bug, is:

plugins {
    java
    id("org.springframework.boot") version "3.2.3"
}

repositories {
    mavenCentral() {
        content {
            excludeGroup("com.oracle.database.jdbc")
        }
    }
}

dependencies {
    implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) {
        (this as ExternalModuleDependency).exclude(group = "com.oracle.database.jdbc")
    }
    implementation("com.oracle.database.jdbc:ojdbc11")
}
jonathanq commented 6 months ago

That solves the error I was getting - nice find.

So using the platform exclusion changes the error to just that it can't resolve the missing BOM file. Sorry if this is a dumb question - but is there a way to make the rest of the Spring Boot dependencies usable?

For example:

dependencies {
    implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) {
        (this as ExternalModuleDependency).exclude(group = "com.oracle.database.jdbc")
    }

    implementation("org.springframework.cloud:spring-cloud-gateway-mvc:4.+")
}

Will still fail with missing Oracle bom

> Task :compileJava FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Could not resolve all files for configuration ':compileClasspath'.
   > Could not resolve org.springframework.boot:spring-boot-dependencies:3.2.3.
     Required by:
         project :
      > Could not resolve org.springframework.boot:spring-boot-dependencies:3.2.3.
         > Could not parse POM maven/org/springframework/boot/spring-boot-dependencies/3.2.3/spring-boot-dependencies-3.2.3.pom
            > Could not find com.oracle.database.jdbc:ojdbc-bom:21.9.0.0.
   > Could not resolve org.springframework.cloud:spring-cloud-gateway-mvc:4.+.
     Required by:
         project :
      > Could not resolve org.springframework.cloud:spring-cloud-gateway-mvc:4.1.1.
         > Could not parse POM maven/org/springframework/cloud/spring-cloud-gateway-mvc/4.1.1/spring-cloud-gateway-mvc-4.1.1.pom
            > Could not resolve org.springframework.cloud:spring-cloud-gateway:4.1.1.
               > Could not resolve org.springframework.cloud:spring-cloud-gateway:4.1.1.
                  > Could not parse POM maven/org/springframework/cloud/spring-cloud-gateway/4.1.1/spring-cloud-gateway-4.1.1.pom
                     > Could not resolve org.springframework.cloud:spring-cloud-build:4.1.0.
                        > Could not resolve org.springframework.cloud:spring-cloud-build:4.1.0.
                           > Could not parse POM maven/org/springframework/cloud/spring-cloud-build/4.1.0/spring-cloud-build-4.1.0.pom
                              > Could not resolve org.springframework.cloud:spring-cloud-build-dependencies:4.1.0.
                                 > Could not resolve org.springframework.cloud:spring-cloud-build-dependencies:4.1.0.
                                    > Could not parse POM maven/org/springframework/cloud/spring-cloud-build-dependencies/4.1.0/spring-cloud-build-dependencies-4.1.0.pom
                                       > Could not resolve org.springframework.boot:spring-boot-dependencies:3.2.0.
                                          > Could not resolve org.springframework.boot:spring-boot-dependencies:3.2.0.
                                             > Could not parse POM maven/org/springframework/boot/spring-boot-dependencies/3.2.0/spring-boot-dependencies-3.2.0.pom
                                                > Could not find com.oracle.database.jdbc:ojdbc-bom:23.3.0.23.09.

I am assuming as long as the com.oracle.database.jdbc:ojdbc-bom is a dependency of the spring-boot-dependencies there is no way to use it without including that. Excluding the BOM is not enough as it's still a required dependency.

wilkinsona commented 6 months ago

Can you share a build script that reproduces that error? I can see that you're using Spring Cloud which you haven't mentioned thus far.

jonathanq commented 6 months ago

I commented out the cloud-gateway. I was trying to use that in a project. But even without that, this gradle file doesn't work when you try to run the application with ./gradlew bootRun

plugins {
    java
    id("org.springframework.boot") version "3.2.3"
    id("io.spring.dependency-management") version "1.1.4"
}

java {
    sourceCompatibility = JavaVersion.VERSION_17
}

group = "dev.quail"
version = "1.0"

dependencies {
    implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) {
        (this as ExternalModuleDependency).exclude(group = "com.oracle.database.jdbc")
    }

    //implementation("org.springframework.cloud:spring-cloud-gateway-mvc:4.+")

    implementation("org.springframework.boot:spring-boot-starter-web")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}
wilkinsona commented 6 months ago

You should remove the dependency management plugin. Using a platform dependency with an exclusion is intended as a workaround for the fact that the feature requested in this issue does not exist. This works for me:

plugins {
    java
    id("org.springframework.boot") version "3.2.3"
}

java {
    sourceCompatibility = JavaVersion.VERSION_17
}

repositories {
    mavenCentral() {
        content {
            excludeGroup("com.oracle.database.jdbc")
        }
    }
}

group = "dev.quail"
version = "1.0"

dependencies {
    implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) {
        (this as ExternalModuleDependency).exclude(group = "com.oracle.database.jdbc")
    }
    implementation("org.springframework.boot:spring-boot-starter-web")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}
jonathanq commented 6 months ago

Can you run a basic SpringBoot app with that? When I try to run it with Gradle I just get the error about the missing dependency (run using ./gradlew bootRun

 ./gradlew bootRun
> Task :compileJava FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Could not resolve all files for configuration ':compileClasspath'.
   > Could not resolve org.springframework.boot:spring-boot-dependencies:3.2.3.
     Required by:
         project :
      > Could not resolve org.springframework.boot:spring-boot-dependencies:3.2.3.
         > Could not parse POM /maven/org/springframework/boot/spring-boot-dependencies/3.2.3/spring-boot-dependencies-3.2.3.pom
            > Could not find com.oracle.database.jdbc:ojdbc-bom:21.9.0.0.

That is with a basic Java app defined:

package dev.quail;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class QualDevApp {

    public static void main(final String[] args) {
        SpringApplication.run(QualDevApp.class, args);
    }
}
wilkinsona commented 6 months ago

Yes, I could. Perhaps it's because you genuinely have no access to com.oracle.database.jdbc:ojdbc-bom:21.9.0.0 whereas I am relying on the exclude group configuration when I declare the Maven Central repository?

aluferraz commented 5 months ago

Any workarounds ? I'm facing the same issue. My company's internal repo doesn't have any com.oracle.database.jdbc version.

wilkinsona commented 5 months ago

Yes, use Gradle's platform support as described above. Beyond that, https://github.com/spring-projects/spring-boot/issues/39945 will help once it has been released later this month.

aluferraz commented 4 months ago

Thanks! I was not able to compile using that approach. Since I don't need ojdbc, I created a local maven repo holding only the XML Pom (no jar files), and did this :

    repositories {
        maven {
.....
 exclusiveContent {
            forRepository {
                maven {
                    name = "Local"
                    url = uri("file://${System.getProperty('user.dir')}/repo/maven2")
                    metadataSources {
                        // This is to say, we only have the artifacts (a pom, jar, ...).
                        mavenPom()
                    }
                    content {
                        // We only want to look for things from these group/module/versions in our "repo"
                        includeGroup("com.oracle.database.jdbc")
                        includeModule("com.oracle.database.jdbc", "ojdbc-bom")
                        includeVersion("com.oracle.database.jdbc", "ojdbc-bom", "21.9.0.0")
                        includeVersion("com.oracle.database.jdbc", "ojdbc-bom", "23.3.0.23.09")
                        includeVersion("com.oracle.database.jdbc", "ojdbc-bom", "19.3.0.0")
                        includeVersion("com.oracle.database.jdbc", "ojdbc-bom", "21.7.0.0")

                    }
                }
            }
            filter {
                // this repository *only* contains artifacts with group "com.oracle.database.jdbc"
                includeGroup("com.oracle.database.jdbc")
            }
        }
...