Transitive dependency resolution in WAR-plugin removes required dependency


(Michael Oberwasserlechner) #1

Hi,

I’m currently using Gradle 1.4 to build a project based on GWT and Spring.

Some GWT dependencies are only required while compiling Java to Javascript and need not be included in the WAR-file, so I use the WAR plugin’s ‘providedCompile’ and ‘providedRuntime’ configurations to keep control of such dependencies.

As soon as I try to actually build the WAR-File the transitive dependencies, which appear in both the ‘runtime’ and the ‘povidedRuntime’ configuration are removed in the war task. I think its because the configurations are resolved to the jar - files and the intersection of both FileCollections removes also required dependency jars.

war {
  // default behaviour according to docs
  // http://www.gradle.org/docs/current/dsl/org.gradle.api.tasks.bundling.War.html#org.gradle.api.tasks.bundling.War:classpath
  classpath configurations.runtime - configurations.providedRuntime
}

In my case the ‘aopalliance-1.0.jar’ was missing. See the dependency insight for it below.

gradlew dependencyInsight --dependency aopalliance
:dependencyInsight
aopalliance:aopalliance:1.0
+--- com.google.inject:guice:3.0
|
  +--- com.gwtplatform:gwtp-dispatch-client:1.0-RC-2
|
  |
  \--- compile
|
  +--- com.gwtplatform:gwtp-clients-common:1.0-RC-2
|
  |
  +--- compile
|
  |
  +--- com.gwtplatform:gwtp-mvp-client:1.0-RC-2
|
  |
  |
  \--- compile
|
  |
  \--- com.gwtplatform:gwtp-dispatch-client:1.0-RC-2 (*)
|
  +--- com.gwtplatform:gwtp-crawler:1.0-RC-2
|
  |
  \--- compile
|
  +--- com.google.gwt.inject:gin:2.0.0
|
  |
  \--- compile
|
  \--- com.google.inject.extensions:guice-assistedinject:3.0
|
       \--- com.google.gwt.inject:gin:2.0.0 (*)
+--- org.springframework:spring-aop:3.1.3.RELEASE
|
  +--- org.springframework:spring-tx:3.1.3.RELEASE
|
  |
  +--- compile
|
  |
  +--- org.springframework:spring-orm:3.1.3.RELEASE
|
  |
  |
  \--- compile
|
  |
  \--- org.springframework:spring-jdbc:3.1.3.RELEASE
|
  |
       \--- org.springframework:spring-orm:3.1.3.RELEASE (*)
|
  +--- org.springframework:spring-context:3.1.3.RELEASE
|
  |
  +--- org.springframework:spring-webmvc:3.1.3.RELEASE
|
  |
  |
  \--- compile
|
  |
  +--- org.springframework:spring-tx:3.1.3.RELEASE (*)
|
  |
  +--- com.gwtplatform:gwtp-dispatch-server-spring:1.0-RC-2
|
  |
  |
  \--- compile
|
  |
  +--- org.springframework:spring-context-support:3.1.3.RELEASE
|
  |
  |
  \--- org.springframework:spring-webmvc:3.1.3.RELEASE (*)
|
  |
  \--- org.springframework:spring-web:3.1.3.RELEASE
|
  |
       +--- org.springframework:spring-webmvc:3.1.3.RELEASE (*)
|
  |
       \--- com.gwtplatform:gwtp-dispatch-server-spring:1.0-RC-2 (*)
|
  \--- org.springframework:spring-web:3.1.3.RELEASE (*)
+--- org.springframework:spring-tx:3.1.3.RELEASE (*)
\--- org.springframework:spring-web:3.1.3.RELEASE (*)
  (*) - dependencies omitted (listed previously)

Beside other the aopalliance dependency is configured like this

dependencies {
  providedRuntime ("com.google.gwt.inject:gin:2.0.0")
  runtime ("org.springframework:spring-aop:${springVersion}")
}

As a work around I remove the ‘provided’ - dependencies not by comparing files-names but by comparing the artifact names of my first-level dependencies and resolve it later.

configurations {
    warDeps
}
  war {
 def r = configurations.runtime.allDependencies
 def p = configurations.providedRuntime.allDependencies
 r.each {
  def compareStr = "${it.group}:${it.name}:${it.version}"
  def remove = false
  p.each { it1 ->
   if (compareStr == "${it1.group}:${it1.name}:${it1.version}") {
    remove = true
   }
  }
      if (!remove) {
   project.getDependencies().add("warDeps", it);
  }
 }
 classpath = configurations.warDeps
 classpath sourceSets.main.output.classesDir
     // Compiled (generated) classes
 classpath sourceSets.main.output.resourcesDir
    // Generated resources
}

Is there another, better solutions for this problem?

Thanks for your help.

Michael


#2

By putting a dependency in the ‘providedRuntime’ configuration, you are telling Gradle not to include the jar as a dependency, because it is “provided” by the container at runtime. Gradle assumes that all of the transitive dependencies are also “provided” by the container, which makes sense (why would a container provide a runtime library without it’s dependencies.

It would probably be a good idea to use your own custom configuration instead of ‘providedRuntime’ for GWT compile-time dependencies. By setting these dependencies as ‘transitive=“false”’ you should be able to do something like:

war {
     classpath configurations.runtime - configurations.gwtCompile
}