Cannot create a jar with its dependencies

Hi,

I am trying to create a jar with its dependencies.
I have two sub-projects “app” and “lib” with “app” depending on “lib”.
The ‘jar’ task fails and gives this message:

> Task :app:jar FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:jar'.
> Cannot convert the provided notation to a File or URI: ZIP '/Users/ ... /lib/build/libs/lib.jar'.
  The following types/formats are supported:
    - A String or CharSequence path, for example 'src/main/java' or '/usr/include'.
    - A String or CharSequence URI, for example 'file:/usr/include'.
    - A File instance.
    - A Path instance.
    - A Directory instance.
    - A RegularFile instance.
    - A URI or URL instance.
    - A TextResource instance.

I reproduce this error with Gradle versions 7.1.1 then 7.0 then 6.9 (I have not tested other versions).
The “build.gradle” file for “app” is as follows:

plugins {
    id 'java-library'
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(15)
    }
}

repositories {
    mavenCentral()
}

dependencies {
	implementation fileTree(dir: '/Users/ ... /lib/build/libs', include: '*.jar')
}

tasks.named('jar') {
    manifest {
        attributes('Implementation-Title': project.name,
                   'Implementation-Version': '1.0'
                   'Main-Class': 'com.mypackage.TestJarWithDependencies')
        
        from configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

Since I haven’t found any different examples to create a jar with its dependencies, I’m wondering why there is this error message.
But above all, I would like to know how to create a nice jar file with all its dependencies.

In this test example I access a personal library but the final goal is to create a jar that uses Java libraries such as JavaFx, Hibernate etc.

Is being called from the context of the manifest configuration, which is trying to convert the runtime classpath configuration into a manifest file to be merged.

Move the from call outside the manifest {} block in order to call from of the Jar task.

Also, calling from configurations.runtimeClasspath... is going to resolve the configuration during Gradle’s configuration phase. To defer it to the execution of the jar task, pass from a closure instead:

from { configurations.runtimeClasspath... }

When doing this you should also tell Gradle that the runtimeClasspath configuration is an input to the task:

tasks.named( 'jar' ) {
    inputs.files( configurations.runtimeClasspath )
    ...
}

With these newly declared inputs, Gradle can infer that the jar task depends on the lib project’s jar task, but only if you declare a proper project dependency instead of using fileTree:

dependencies {
    implementation project( ':lib' )
}

Side Note: Declaring the dependency as a project dependency will also ensure that lib's classes/jar are built before app's classes and also include any transitive dependencies from lib.

Thank you Mr. Doré, I now get exactly the expected result.

I also suggest to take a look on the excellent Shadow plugin: Gradle - Plugin: com.github.johnrengelman.shadow
I think it is exactly what you need plus it takes care of some of the less obvious edge cases.

Thanks for the info Sergey.
I had explored this plugin (and even tried) without success. I had understood that he was of great help in particular and difficult cases. I will have to explore it again with a new eye.
Depending on the case, the world of Gradle is difficult to access, even for an old developer (or perhaps especially an old developer).
Fortunately, the gurus of the IT community show kindness and share their knowledge.