Convert Maven `maven-assembly-plugin` to Gradle - 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.

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 NoClassDefFoundError in jar dependency

I have developed a custom Gradle plugin and assembled as jar. This plugin has one dependency:
plugin/build.gradle
dependencies {
compile 'com.jcraft:jsch:0.1.53'
}
I have included my plugin in another consumer project (as jar in libs):
consumer/build.gradle
apply plugin: 'gg-release-plugin'
buildscript {
repositories {
flatDir {
dirs 'libs'
}
mavenCentral()
}
dependencies {
classpath 'com.myplugin.plugin:myplugin:1.0'
}
}
Everything works fine, but when code that uses classes of the dependency com.jcraft:jsch:0.1.53 is executed, I get an error:
java.lang.NoClassDefFoundError: com/jcraft/jsch/JSch
What am I doing wrong? How can I include the dependencies in jar file?
Seems, you've created a plugin jar library with compile time depnedency, that is not included anywhere in your final jar.
You can try to create your plugin jar as a fat jar, using Gradle FatJar plugin or something else. In that case, you'll have a single jar with all the dependent classes inside. But this could lead to problems, if someone will use the same library.
Or you can try to provide a JSch library together with your plugin jar and make a consumer build script dependency like:
buildscript {
repositories {
flatDir {
dirs 'libs'
}
mavenCentral()
}
dependencies {
classpath 'com.myplugin.plugin:myplugin:1.0'
classpath 'com.jcraft:jsch:0.1.53'
}
}
As I know, if you use a Maven repo to publish your plugin, you can provide a pom.xml to describe all the plugin's dependencies, but as I see, you are using a flatDir for it, so, it seems not to be possible.

You can't change configuration 'providedRuntime' because it is already resolved

I am using Gradle 2.0 with Groovy 2.3.3.
When I run the build below I get the error > You can't change configuration 'providedRuntime' because it is already resolved!
Other posts and release notes suggest that it is to do with +=, however, I'm not using that operator so I am a bit confused.
apply plugin: 'war'
repositories {
mavenCentral()
}
//We don't want transitive dependencies added as we are matching a third-party build
configurations.all {
transitive = false
}
war {
archiveName='gradle.war'
from(configurations.providedRuntime.files) {
into "app-jars"
}
classpath fileTree('webinf-libs') // adds a file-set to the WEB-INF/lib dir.
}
dependencies {
providedRuntime group: 'com.thoughtworks.xstream', name: 'xstream', version: '1.4.2'
}
Changing war configuration to:
war {
archiveName='gradle.war'
from(configurations.providedRuntime) {
into "app-jars"
}
classpath fileTree('webinf-libs') // adds a file-set to the WEB-INF/lib dir.
}
will solve the issue.
The problem occurred because files was called in war configuration block and then dependencies were added to providedRuntime. Since calling files resolves the configuration (and war block is evaluated at configuration phase) it can't be modified later on.
You can also change order of dependencies and war and it will be the same.

Transitive project dependencies when dependency has a zip artifact

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: ...)).

Resources