Transitive project dependencies when dependency has a zip artifact - gradle

Typically, I define project dependencies simply:
dependencies {
compile project(':someProject')
}
This works well for java projects. However, I have a project that produces a zip artifact:
artifacts {
archives file: zipDistribution.archivePath, type: 'zip', builtBy: zipDistribution
}
And when I do the dependency definition above, I don't get the zip artifact when I iterate over the dependencies in the compile configuration. A jar file is there, but no zip. This, however, gets the zip file:
dependencies {
compile project(path: ':someProject', configuration: 'archives')
}
Great! It works! Except "someProject" has its own dependencies... and we're not getting those transitively any more. Adding transitive: true to the project dependency didn't help, either.
How can I get the project's zip artifact AND the transitive dependencies associated with it? I can add both flavors of dependencies, but I feel there's got to be a way to do it in one dependency definition.

The archives configuration contains the artifacts to be uploaded, but it doesn't contain any dependencies. Try this instead:
dependencies {
runtime ...
}
artifacts {
runtime zipDistribution // assuming this is a `Zip` task
}
dependencies {
compile project(':someProject')
}
Instead of the Java plugin's runtime configuration, the former script can also add dependencies and artifacts to a custom configuration, which would then have to be reflected in the project dependency (project(path: ..., configuration: ...)).

Related

War task of Gradle build adding extra jars than those from dependencies in build.gradle

We have recently migrated to Gradle build and I have added a war that task that has web.xml and dependent jars along with jar created in the jar task.
task testWar(type: War)
{
archiveName 'test.war'
webXml = file('WebContent/WEB-INF/web.xml')
into ('WEB-INF/lib')
{
from configurations.compile
from jar
}
}
This creates the war but the size of WEB-INF/lib is double the size of the libs actually given in dependencies. It might be adding the jars that the dependent jars depend on. But Ant build just works fine with just the dependent jars.
Is there any way to create war with just the jars provided in dependencies?
Note: https://docs.gradle.org/current/userguide/war_plugin.html didnt help as I need all the jars in dependencies, just want to avoid extra dependent jars
You can use gradle dependencies to know which libraries are causing the inclusion of these additional dependencies.
Once you have that then simply exclude the dependency you want to remove from your package.
dependencies {
compile (group: 'org.quartz-scheduler', name: 'quartz', version: '2.3.0') {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
}

How to build a jar from a multi-module project when using Gradle?

I'm working on a multi-module library project which I build with Gradle. I have a dependency to another module of this project in my dependencies section:
dependencies {
compile project(':my-other-module')
}
My problem is that I want to build a .jar file which only contains the local modules in the final file, not its transitive dependencies. I tried this:
jar {
from project(':my-other-module').configurations.compile.collect { zipTree it }
}
but this added all the transitive dependencies as well. I want to create a .jar which only contains my own files, so the users of this library can have their own versions of transitive dependencies. How can I do so?
Further clarification:
I have dependencies declared in my project to external jars like apache-commons. I want these not to be in my resulting .jar file but I want the users of my library to be able to just add my library as a dependency and let Maven/Gradle download the transitive dependencies. I don't want these transitive dependencies to be in the .jar file I deploy to Maven Central. compileOnly is not an option since the dependencies I use like apache-commons are not provided by a framework or a container. They need to be present as compile dependencies. I just want to build and deploy a .jar file which has all the files in my project which has multiple modules.
I am not sure it'll help you or not but, you can try this.
In your build.gradle file, customize your jar task as follows:
// This closure will return the full directory path of folder where your classes are built
ext.moduleClassPath = { moduleName ->
def classOutputDirConst = "/classes/java/main"
return "${project(":${moduleName}").buildDir}${classOutputDirConst}"
}
// Now jar task will include only the built file of specified project
jar {
from(moduleClassPath("projectName1"), moduleClassPath("projectName2"))
}
Check the reference for the from(SourcePaths) method here: Reference: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:from(java.lang.Object[])
Gradle has a compile-only dependency concept, similar to Maven's provided scope:
Compile-only dependencies are distinctly different than regular compile dependencies. They are not included on the runtime classpath and they are non-transitive, meaning they are not included in dependent projects.
The dependencies you don't want can be declared in the compileOnly configuration, rather than compile, eg:
dependencies {
compileOnly 'javax.servlet:servlet-api:2.5'
}
compileOnly is not even visible to unit tests, by default. We change this in a common gradle snippet which we include in each build:
// compileOnly isn't visible to tests by default, add it
plugins.withType(JavaPlugin).whenPluginAdded {
sourceSets {
test.compileClasspath += configurations.compileOnly
test.runtimeClasspath += configurations.compileOnly
}
}
For the second part, for which I believe you want to create a single "fat" jar,
I would suggest creating your jar using the very good Shadow Plugin, rather than manually extending the jar task. By default, the shadow plugin will not include anything in the compileOnly configuration in the resulting jar.

Gradle fails to detect flat dependency

I have a multi-project Gradle build (Gradle 4.4).
And I encountered the following issue.
Let's say I have proj1 project with the following build.gradle:
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
compile name: 'lombok-edge'
}
proj1 has libs folder with lombok-edge.jar. Project is built successfully.
And I have proj2 that imports proj1:
dependencies {
compile project(':proj1')
}
When I try to build the whole project proj1 is build but Gradle fails to build proj2 with an error:
What went wrong:
Could not resolve all files for configuration ':proj2:compileClasspath'.
Could not find :lombok-edge:.
Required by:
project :proj2 > project :proj1
Please advise.
Well, Gradle supports transitive dependencies, but the way how to get a dependency (and therefor any repository information) is not transitive. Gradle (like Maven) does not care where a dependency comes from, as long as it matches a given signature (group, id, version).
In your example, project 1 defines a Maven dependency and can resolve it via the given flatDir repository. Project 2 has dependencies on both project 1 (which is resolved by Gradle) and the transitive Maven dependency. It's the responsibility of project 2 to resolve this dependency and it will check any defined repository, but cannot find it, because the local repository is unkown. This is the reason why the build fails.
If the two projects are related, as they should be if they are both parts of a multi-project build, you should define the local repository in a top-level build.gradle file and a subprojects closure.

Convert Maven `maven-assembly-plugin` to Gradle

I'm converting a Java project from Maven to Gradle.
One of the pom.xml is using maven-assembly-plugin to package dependencies into a single zip file.
I'm using custom configuration to specify the dependencies to package like so:
group = 'com.company'
description = 'projectA'
configurations {
ciPlugin
}
dependencies {
ciPlugin group: 'org.apache.httpcomponents', name: 'httpclient', version:'4.3.1'
}
jar {
into('plugins') {
from configurations.ciPlugin
}
}
This works almost fine beside the fact I have the following files in the resulting zip file:
commons-codec-1.10.jar
commons-logging-1.2.jar
httpclient-4.5.3.jar
httpcore-4.4.6.jar
and when Maven runs it only has httpclient-4.5.3.jar.
Just for clarification, I'm not really packaging httpclient, I'm packaging private artifact but the behavior is the same.
How can I get only the direct dependency without transient ones?
Add the following (e.g. after the dependencies block):
configurations.ciPlugin.transitive = false
This will turn off transitive dependencies for all artifacts in the ciPlugin configuration.

Gradle: how to exclude jar from an ear file?

I have a question regarding excluding a jar file from an ear artifact. My project has the following modules:
project
- ejb_module
- war_module
- ear_module
- other_module
In my ear_module/build.gradle :
dependencies {
deploy project(ejb_module)
earlib project(ejb_module)
deploy project(war_module)
earlib project(war_module)
}
The problem is how I exclude the jar artifact produced from the war_module.
The war_module produces both war and jar artifact. The reason I need the jar artifact is that my other_module depends on it.
A complicated factor is that the war_module has some dependencies that needs to go via earlib.
So my question is how I exclude the war_module.jar from the ear file? It is included both at root and in APP-INF/lib.
I presume in your war_module you are applying both war and java plugins to get a .war. and .jar artifacts ?
Try:
deploy project(path: 'war_module', configuration: 'archives')
earlib project(path: 'war_module', configuration: 'archives')
It should pick up a .war only because if look into the Gradle war plugin code you can see that it overrides the default output of the project, if java plugin was included.
Additionally, war plugin uses java plugin to compile your code under the hood.
You, of course, can simply exclude the artefact from the build by using
config (project){exclude module: 'name'}
but I think this is not the best you can do here.
Try looking into providedRuntime and runtimeOnly configurations depending on which version of Gradle do you use.
If the artefact is used for compilation then compileOnly etc.
This configuration used in dependecies{} will use the jar but will not be going to expose it anywhere else then it should not land in any artefact that you build and this is probably what would fit you the most in your case, but the question wasn't asking about this it's just an advice.
Assume your EAR contains an another existing jar, said xxx.yyy.zzz.jar.
In your ear project's build.gradle, add the following
ext.replacement = 'your.group:xxx.yyy.zzz:your.version'
configurations.all {
resolutionStrategy {
eachDependency { DependencyResolveDetails details ->
// remove to.be.excluded.jar
if (details.requested.group == 'your.group' &&
details.requested.name == 'to.be.excluded' &&
details.requested.version == 'your.version') {
details.useTarget replacement
}
}
}
}
This way, the to.be.excluded.jar will be replaced by xxx.yyy.zzz.jar, that virtually removes it from the EAR.

Resources