Apache CXF transitive dependencies are missing many dependencies when coming from Maven to Gradle

I have a pressing, urgent problem when moving from Maven to Gradle.

My project has only THREE dependencies declared from the Apache CXF framework:

        <!-- SOAP -->

When looking at the resulting transitive dependencies for my runtime classpath, you see this (as an example for cxf-rt-transports-http:

+- com.sun.activation:jakarta.activation:1.2.2
+- com.sun.xml.messaging.saaj:saaj-impl:1.5.3
+- jakarta.annotation:jakarta.annotation-api:1.3.5
+- jakarta.jws:jakarta.jws-api:2.1.0
+- jakarta.xml.soap:jakarta.xml.soap-api:1.4.2
+- jakarta.xml.ws:jakarta.xml.ws-api:2.3.3
+- org.apache.cxf:cxf-core:3.5.0
+- org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1.1

My build.gradle.kts now has exactly these three dependencies:


But have a look at the transitive dependencies this results in for cxf-rt-transports-http:

+- org.apache.cxf:cxf-core:3.5.0

I have great difficulties understanding WHY and WHAT is going on here. There’s even compile time dependencies missing - the imports for

import javax.xml.ws.BindingType
import javax.xml.ws.Provider
import javax.xml.ws.WebServiceProvider
import javax.xml.ws.soap.SOAPBinding

Do not compile anymore using Gradle.

Can somebody help me to transition to Gradle properly? What option/flag/setting am I missing here?
Why is Maven behaving so differently?

The problem is, that the CXF authors had the (by many others evaluated as very bad) idea to have a jdk-version activated profile that adds additional dependencies when you build with Java 9+.

But Gradle only supports a small subset of profile activation policies. (If the info in Gradle's Support for Maven POM Profiles ist still correct, then only ones activated by default and ones activated by absence of a system property.)

In this issue I request support for jdk-version activated profiles as the CXF guys are not the only ones doing it that way, they just additionally greatly overuse it by declaring a bunch of dependencies for all artifacts by having the profile in the parent POM: Support for `jdk` activated profiles in POMs · Issue #19224 · gradle/gradle · GitHub
You might want to thumbs-up and subscribe that issue.

In the meantime there are two solutions.
The poor-man’s solution is to just declare those dependencies yourself, e. g. as runtimeOnly as they are not your dependencies.
The ones you use yourself in your code should be declared explicitly anyway instead of bing used transitively.

The semantically better work-around is to use a component metadata rule to fix up the wrong metadata, like this one in the setting script:

dependencyResolutionManagement {
    // work-around for https://github.com/gradle/gradle/issues/19224
    components {
        all {
            if (id.group != "org.apache.cxf") {
            check(id.version == "3.5.0") {
                "Please configure Java 9+ dependencies for $id"
            listOf("compile", "runtime").forEach { variant ->
                withVariant(variant) {
                    withDependencies {
            withVariant("runtime") {
                withDependencies {
1 Like

Thanks so much! I was already suspecting, that Apache CXF does something strange and out of the ordinary. Currently, I added my missing dependencies manually (workaround #1) but your script, as I understand it, basically does the same work manually, but also checks to make sure that if the version 3.5.0 is ever touched, I get a message, asking for updating the dependency fix. Is that right?

Currently, my only way to find what is actually missing is to also have a working maven build ready to run. But I wanted to get rid of this. How can I make sure to manually get to the missing dependencies once the version is raised? Is there a better way?

It basically also adds the deps manually, yes.
But it adds them to the proper variants, so is semantically better.
And yes, it will yell at you if you update the version to double-check the work-around versions.
You can simply look at that cxf-parent POM at https://repo1.maven.org/maven2/org/apache/cxf/cxf-parent/3.5.0/cxf-parent-3.5.0.pom, there you find a jdk-activated profile that adds the dependencies. There you can find the versions (or the properties from which the version can be read and the scope. Add all compile (or default) scoped to compile and runtime variant and all runtime scoped like saaj-impl to runtime variant.

1 Like

Sorry. Did not read the “settings” part. I’ll put it into settings.gradle.kts!

1 Like

You can also put it in the build script if you want, you just have to put it into a different container then.
But I would do it in the setting script, yes.

Is there one more trick to make it work…? It compiles fine in settings.gradle.kts - but it does not do anything.
I added a println(“In $id now”) right before the if (id.group != “org.apache.cxf”) check - and during build it only ever is there twice, printing:

In gradle:gradle:7.4 now
In gradle:gradle:7.4 now

Do you have it in the correct settings script?
Did you actually try to resolve the configuration or just do something like ./gradlew help?
Actually I wonder where you got that gradle:gradle:7.4 dependency from, never seen that.

Oha. Now we have differences in IntelliJ Gradle and “normal” gradlew execution!

I have the correct settings.gradle.kts in my project’s root. (There is no other settings file of that kind anywhere). I added your snippet and pressed the IntelliJ button to reload Gradle which pops up when anything in the build settings is changed.
Then, in the Build tab of IntelliJ you see the two gradle:gradle:7.4 outputs… And looking at my dependency tree in the Gradle tab, nothing has changed regarding CXF.

BUT: on the command line, executing gradlew build works exactly like promised: you see all my dependencies printed as I expected!

Why does having ONE problem always lead to new problems…? :wink:

Just to try this: what container do I have to put this in to make it work in build.gradle.kts? And why is the settings the right place? Basically: what context does this method “dependencyResolutionManagement” need to be found?

Ah, that’s then this problem to thumbs-up and follow: dependencyResolutionManagement.components is ignored during IDE import into IntelliJ · Issue #18827 · gradle/gradle · GitHub
I usually don’t see it for that case as I tend to declare the dependencies I use directly and try to never rely on transitive dependencies.
It also contains the version for the build script, basically in dependencies instead of in dependencyResolutionManagement.

As to why in the setting script, I like to do things in the central place that can be done there. This way it automatically is there for all projects where this dependency might also be added in the future without the chance to forget it. :slight_smile:

1 Like

You really went the same path of problems I am facing… Incredible. Thanks so much. I owe you a beer…
BTW: opened a bug at JetBrains… minutes before I read your answer…

1 Like