gradlebuild.gradledependency-management

how to enforce the constraints in gradle dependencies if they come from 2 different packages


I'm trying to force some dependencies in gradle but I'm strugle to making this work.

I read the documentation and tried this: https://docs.gradle.org/current/userguide/dependency_management.html#controlling_transitive_dependencies

build.gradle:

dependencies {
    implementation (group: 'com.google.protobuf', name: 'protobuf-java-util', version: '3.19.4')
    constraints {
        implementation('com.google.code.gson:gson-2.8.9')
    }

    implementation (group: 'io.confluent', name: 'kafka-connect-s3', version: '5.5.7')
    constraints {
        implementation('com.google.code.gson:gson-2.8.9')
        implementation('org.apache.hadoop:hadoop-common-3.3.1')
    }

But when I check the dependencies this is totally ignored. How would I be able to enforce in this case that I'm using the 2.8.9

$ ./gradlew -q dependencyInsight --dependency com.google.code.gson:gson
   variant "compile" [
      org.gradle.status              = release (not requested)
      org.gradle.usage               = java-api
      org.gradle.libraryelements     = jar (compatible with: classes)
      org.gradle.category            = library

      Requested attributes not found in the selected variant:
         org.gradle.dependency.bundling = external
         org.gradle.jvm.version         = 8
   ]
   Selection reasons:
      - By conflict resolution : between versions 2.8.6 and 2.2.4

com.google.code.gson:gson:2.8.6
\--- com.google.protobuf:protobuf-java-util:3.19.4
     \--- compileClasspath

com.google.code.gson:gson:2.2.4 -> 2.8.6
\--- org.apache.hadoop:hadoop-common:2.10.1
     \--- io.confluent:kafka-connect-s3:5.5.7
          \--- compileClasspath

A web-based, searchable dependency report is available by adding the --scan option.

By the output I see that my constraint is not even considered so is there any tip what I might be doing wrong?

Thank you for any feedback.

UPDATE: I manage to make this work in a different way but I don't think this is how you are supposed to do it.

build.gradle:

implementation (group: 'com.google.protobuf', name: 'protobuf-java-util', version: protobufVersion) {
    exclude group: 'com.google.code.gson', module: 'gson'
}
implementation (group: 'io.confluent', name: 'kafka-connect-s3', version: confluentVersion) {
    exclude group: 'org.apache.hadoop', module: 'hadoop-common'
}

implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.9', transitive: true
implementation group: 'org.apache.hadoop', name: 'hadoop-common', version: '3.3.1',  transitive: true
constraints {
    implementation('com.google.code.gson:gson-2.8.9') {
        because 'ADA-1033 and ADA-1042 (VULN-4102, VULN-4090)'
    }
    implementation('org.apache.hadoop:hadoop-common-3.3.1')
}


$ ./gradlew -q dependencyInsight --dependency com.google.code.gson:gson
   variant "compile" [
      org.gradle.status              = release (not requested)
      org.gradle.usage               = java-api
      org.gradle.libraryelements     = jar (compatible with: classes)
      org.gradle.category            = library

      Requested attributes not found in the selected variant:
         org.gradle.dependency.bundling = external
         org.gradle.jvm.version         = 8
   ]
   Selection reasons:
      - By conflict resolution : between versions 2.8.9 and 2.2.4

com.google.code.gson:gson:2.8.9
\--- compileClasspath

com.google.code.gson:gson:2.2.4 -> 2.8.9
\--- org.apache.hadoop:hadoop-common:3.3.1
     \--- compileClasspath

A web-based, searchable dependency report is available by adding the --scan option.

Like I said this seems to work but I don't think I even need the constraint block there if I just force it to be a certain version by declaring a transitive dependency. I would still like to understand why my first example does not work.


Solution

  • One thing to note here is that constraints{} here is not a property of an implementation, it's a sibling. I recommend you consolidate into one constraints section, as having two is needlessly complex, and in your case is leading to redundancy:

    dependencies {
        implementation (group: 'com.google.protobuf', name: 'protobuf-java-util', version: '3.19.4')
        implementation (group: 'io.confluent', name: 'kafka-connect-s3', version: '5.5.7')
    
        constraints {
            implementation('com.google.code.gson:gson-2.8.9')
            implementation('org.apache.hadoop:hadoop-common-3.3.1')
        }
    }
    

    Secondly, your version syntax in your constraints is wrong. You're using hyphens when you need colons. So proper syntax would be:

        constraints {
            implementation('com.google.code.gson:gson:2.8.9')
            implementation('org.apache.hadoop:hadoop-common:3.3.1')
        }
    

    You can find a snippet of the exact syntax you need on mvnrepository https://mvnrepository.com/artifact/com.google.code.gson/gson/2.8.9#gradle-short-kotlin https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common/3.3.1#gradle-short-kotlin

    So the configuration to use would be

    dependencies {
        implementation (group: 'com.google.protobuf', name: 'protobuf-java-util', version: '3.19.4')
        implementation (group: 'io.confluent', name: 'kafka-connect-s3', version: '5.5.7')
    
        constraints {
            implementation('com.google.code.gson:gson:2.8.9')
            implementation('org.apache.hadoop:hadoop-common:3.3.1')
        }
    }