Gradle NoClassDefFoundError in jar dependency - gradle

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.

Related

How to change name of java library when build with gradle?

I'm trying to build a java library for my other java projects. I'm also trying to learn gradle. There is a tutorial : https://docs.gradle.org/current/samples/sample_building_java_libraries.html shows how to build libraries with gradle.
But somehow when I use gradlew build it always gives me lib-< version >.jar and creates a folder called lib and I can't change it.
This is my settings.gradle
rootProject.name = 'myOwnLibrary'
include('lib')
this is my build.gradle (inside lib folder)
plugins {
// Apply the java-library plugin for API and implementation separation.
id 'java-library'
}
version = "0.1.1"
tasks.named('jar') {
manifest {
attributes('Implementation-Title': project.name,
'Implementation-Version': project.version)
}
}
repositories {
// Use JCenter for resolving dependencies.
jcenter()
}
dependencies {
// Use JUnit test framework.
testImplementation 'junit:junit:4.13'
// This dependency is exported to consumers, that is to say, found on their compile classpath.
api 'org.apache.commons:commons-math3:3.6.1'
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:29.0-jre'
}
With Kotlin DSL example, you can add in your tasks jar the following snippet:
tasks.jar {
manifest {
attributes(mapOf("Implementation-Title" to rootProject.name,
"Implementation-Version" to project.version))
}
archiveBaseName.set(rootProject.name)
}
where rootProject.name, is the value localized into settings.gradle.kts file.

build.gradle buildscript dependencies vs. dependencies?

Can someone explain to me how depedencies listed in the "buildscript" in the build.gradle file are different than regular dependencies listed in the dependencies block { } ? and why they have to be listed with the syntax "implementation"? I've googled this and responses say the dependencies in the buildscript and used to "build the project" but I don't understand this? can anyone give a more clear picture and answer?
buildscript:
buildscript
{
repositories
{
maven {
url 'myMavenFeed'
credentials {
username "myUsername"
password myPassword
}
}
mavenCentral()
jcenter()
}
dependencies
{
classpath "com.microsoft.azure.sdk.iot:iot-device-client:1.14.1"
}
}
Dependencies block:
dependencies
{
compile group: 'com.microsoft.azure.sdk.iot', name: 'iot-device-client', version: '1.16.0'
}
Can someone explain to me how depedencies listed in the "buildscript" in the build.gradle file are different than regular dependencies listed in the dependencies block { } ?
Dependencies defined in the buildscript { } block are dependencies to use to build your project. These dependencies are available to use in your Gradle build file (build.gradle or build.gradle.kts)
Dependencies defined in the dependencies { } are for your application code.
So for your samples in your questions, does it make sense for Gradle (the build system) to have iot-device-client on its classpath? Why does a build system need iot-device-client on its classpath to build your project? It doesn't make sense therefore it should be removed.
Now let's say you are developing an application the requires some functionality or class from iot-device-client. You need a way to add this library to your application's code/classpath. You when then declare it as a dependency as you have done above:
dependencies {
implementation("com.microsoft.azure.sdk.iot:iot-device-client:1.16.0")
}
References:
External dependencies for the build script
Declaring depenedncies
and why they have to be listed with the syntax "implementation"?
implementation is known as a configuration: A Configuration represents a group of artifacts and their dependencies
There are many more configurations depending on the plugins you apply to your project. For example, if you apply the Java plugin:
plugins {
id("java")
}
The following configurations are available to use:
implementation
compileOnly
compileClasspath
...and many more
Each one has their own meaning/usage and I strongly suggest reading about them here.

Using a gradle plugin before loading other plugins in the buildscript

I have my own gradle plugin that contains a file with versions for other plugins. Currently, whenever I make a new project, I have to copy them over as I can't use the versions from the plugin.
Is there anyway to load my plugin, apply it, and then load other plugins afterwards? Currently, I can only do this for the project myself when I make my plugin model named buildSrc, as it automatically adds it to other modules.
Example of what I want to achieve:
buildscript {
repositories {
google()
jcenter()
maven { url 'https://maven.fabric.io/public' }
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "ca.allanwang:kau:$kau_version"
}
// Apply plugin before other dependencies so I can use it
apply plugin: "ca.allanwang.kau"
dependencies {
classpath kauPlugin.android
classpath kauPlugin.kotlin
classpath kauPlugin.androidMaven
classpath kauPlugin.playPublisher
classpath kauPlugin.dexCount
classpath kauPlugin.gitVersion
classpath kauPlugin.spotless
}
wrapper.setDistributionType(Wrapper.DistributionType.ALL)
}
and how it looks like when I have the plugin as a module in my main project:
buildscript {
repositories {
google()
jcenter()
maven { url 'https://maven.fabric.io/public' }
maven { url "https://plugins.gradle.org/m2/" }
}
apply plugin: "ca.allanwang.kau"
dependencies {
classpath kauPlugin.android
classpath kauPlugin.kotlin
classpath kauPlugin.androidMaven
classpath kauPlugin.playPublisher
classpath kauPlugin.dexCount
classpath kauPlugin.gitVersion
classpath kauPlugin.spotless
}
wrapper.setDistributionType(Wrapper.DistributionType.ALL)
}
You should be able to achieve what you want by combining different things:
Define your versions in a Plugin<Settings> that you apply in you settings.gradle(.kts) by leveraging the fact that the Settings object is ExtensionAware
Define your plugin classpath in that same settings file using pluginManagement
Apply plugins in your projects, without specifying a version - see this example for a simpler version that does not define versions through pluginManagement
Example: https://github.com/ljacomet/setttings-plugin-props with the plugin in buildSrc but it could be published and used as a binary plugin without any problem.

How Do We Run a Gradle Dependency Report for Plugins?

Running gradle dependencies lists compile-time dependencies. IOW, it reports direct and transitive dependencies coming from the dependencies closure for the subproject.
What is the equivalent means of determining the transitive dependencies being used by Gradle plugins, the ones specified by the dependencies closure in the buildscript closure?
For example, suppose I have this top-level build.gradle file in an Android project:
buildscript {
repositories {
jcenter()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.1'
classpath 'com.apollographql.apollo:gradle-plugin:0.3.1-SNAPSHOT'
}
}
allprojects {
repositories {
jcenter()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
}
How do I find out what transitive dependencies are being pulled in by the com.apollographql.apollo:gradle-plugin:0.3.1-SNAPSHOT dependency?
Gradle provides various help tasks. A list of them is available via gradle tasks -all.
To access the buildscript dependencies, one can use the gradle buildEnvironment command, as described in the Gradle docs:
4.7.5. Listing project buildscript dependencies
Running gradle buildEnvironment visualises the buildscript dependencies of the selected project, similarly to how gradle dependencies visualises the dependencies of the software being built.
As addition, CommonsWare stated, that the command must be executed from the project directory.

Gradle custom plugin dependencies

If a have a custom plugin which handles the building and deploying of a specific component, where do I list the dependencies (other components in my system) which are required for the build?
Dependencies for your Gradle plugins should be listed in the buildscript portion of the build.gradle file. See this chapter of the User Guide, which also has an example:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.4.1"
}
}
apply plugin: "com.jfrog.bintray"
If your custom plugin depends on jar files on your local machine, I gather that you need to add those files as a "flatDir" repository in the repositories entry, as described here:
repositories {
flatDir {
dirs 'lib1', 'lib2'
}
}

Resources