I have build.gradle in front of me and there are some dependencies declared as provided but in documentation I do not see this dependency scope.
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:1.2.4.RELEASE")
....
provided 'backport-util-concurrent:backport-util-concurrent:3.1'
provided 'org.javolution:javolution:5.5.1#jar
....
}
Is this provided by a plugin? If so how do I found out which plugin this belongs to?
What is the difference between provided and runtime dependency scope in Gradle?
What is provided scope?
Suppose that a jar is needed to compile your code, but the jar is present in the production environment library collection. Then you don't need to package the jar with your project archives. To support this requirement, Maven has a scope named provided. If you declare any jar dependency as provided, then this jar will be present in your classpath during compilation but will not be packaged with your project archive.
provided scope is very useful, particularly in web applications. For example, servlet-api.jar is needed to be present in your classpath to compile your project, but you don't need this to package servlet-api.jar file with your war. With provided scope one can achieve this requirement.
There is no Scope defined in Gradle java plugin named provided. Also not in war or android plugins. If you want to use provided scope in your project, then you have to define it in your build.gradle file. Following is the code snippet to declare provided scope in gradle:
configurations {
provided
}
sourceSets {
main { compileClasspath += configurations.provided }
}
Now, your second question:
What is the difference between provided and runtime dependency scope in Gradle?
To answer this question first I will define compile dependency. compile dependencies are dependencies, those are necessary to compile your code. Now imagine that if your code uses a library named X then you must declare X as your compile-time dependency. Also imagine that X uses another library Y internally, and you declared Y as your runtime dependency.
During compilation, Gradle will add X into your classpath but will not add Y. Since, Y is not required for compilation. But it will package both X and Y with your project archive since both X and Y are necessary to run your project archive in the production environment. Generally, all the dependencies needed in the production environment are known as runtime dependency.
In Gradle official documentation, it says that runtime dependency are "the dependencies required by the production classes at runtime. By default, also includes the compile time dependencies.".
Now, if you've read this far, then you already know that provided is a compile dependency that we don't want to be present in the runtime dependency (basically, we don't want it to package with the project archive).
Following is an illustration of provided and runtime scope. Here, compile refers to the dependencies that are required to compile the project and non-compile refers to the dependencies that are not required for project compilation.
As from Gradle 2.12, you can use the compileOnly option.
See
https://blog.gradle.org/introducing-compile-only-dependencies
For further clarification, as of the latest version, Gradle 5.5 has compileOnly (same as provided) and runtimeOnly options. The new default "compile and runtime" option is implementation.
Updating the answer as per the latest gradle versions.
From gradle's official documentation at below link:
https://docs.gradle.org/current/userguide/upgrading_version_5.html
Deprecations
Dependencies should no longer be declared using the compile and runtime configurations. The usage of the compile and runtime
configurations in the Java ecosystem plugins has been discouraged
since Gradle 3.4.
The implementation, api, compileOnly and runtimeOnly configurations should be used to declare dependencies and the compileClasspath and
runtimeClasspath configurations to resolve dependencies.
More so, the compile dependency configuration has been removed in the recently released Gradle 7.0 version.
If you try to use compile in your Gradle 3.4+ project you’ll get a warning like this:
Deprecated Gradle features were used in this build, making it
incompatible with Gradle 7.0. Use ‘–warning-mode all’ to show the
individual deprecation warnings.
You should always use implementation rather than compile for dependencies, and use runtimeOnly instead of runtime.
War plugin
The War plugin extends the Java plugin to add support for assembling web application WAR files. It disables the default JAR archive
generation of the Java plugin and adds a default WAR archive task.
The War plugin adds two dependency configurations:
providedCompile
providedRuntime
Adding an entry to providedCompile or providedRuntime will cause that dependency to be excluded from the war file.
Use providedCompile if you have source that relies on some classes
for compiling.
Use providedRuntime if you use it for testing and not
compiling.
Example:
providedCompile 'org.springframework.boot:spring-boot-starter-tomcat:1.1.6.RELEASE'
The above JAR and its transitive dependency will only be available at compile time but it will not be available at runtime. It means, those JAR will not be included in war archive.
Related
I tried to add 3rd party dependencies in gradle.properties as below
dependencies {
pmd fileTree(dir: "${lib}/aspectj-1.9.4", includes: ['*.jar'])
// OR below
// pmd 'org.aspectj:aspectjtools:1.9.4'
// OR even below also causes same problem.
// pmdAux 'org.aspectj:aspectjtools:1.9.4'
}
It causes error as java.lang.ClassNotFoundException: net.sourceforge.pmd.PMD what can be issue here? how to overcome?
Ref:
https://stackoverflow.com/a/17179486/1665592
https://stackoverflow.com/a/71147569/1665592
It seems that all the dependencies in configuration pmd are replaced once you manually configure the dependency as in your example.
In https://stackoverflow.com/a/71147569/1169968 is explained, that the gradle pmd plugin adds two dependencies configurations: pmd and pmdAux.
pmd defines the classpath that is used to run PMD. It is by default setup by the plugin automatically, dependending on the toolVersion property (see PmdPlugin.java#L194-L201 and PmdPlugin.java#L145-L152).
The gradle documentation about Declaring Dependencies explains, that "Many Gradle plugins add pre-defined configurations to your project". It also seems, that pmd is a default configuration, that is registered/created by AbstractCodeQualityPlugin.java#L98-L116. The configuration name is getToolName().toLowerCase() - so all code-quality plugins define a configuration with the same name as themselves.
When declaring now a dependency like above, it seems that the previously configured dependencies are removed - or in other words: the configuration is replaced.
I don't know, whether this is correct behavior or whether this is a bug. But it seems, once you start declaring such tool dependencies manually, you take over responsibility to declare the complete classpath for PMD. That makes sense, because then the "whole truth" is in your build.gradle/gradle.properties file.
However, since the plugin also has the toolVersion property, this behavior is surprising: The toolVersion property is being ignored, once you declare the dependencies manually.
To fix this, you just need to declare additionally the pmd dependency. So, the following works:
dependencies {
// first define the main PMD dependency
pmd 'net.sourceforge.pmd:pmd-java:6.54.0'
// then declare additional dependencies, e.g. to include your custom rule
pmd 'com.example:myrule:1.0.0'
// or
pmd fileTree(dir: "${lib}/aspectj-1.9.4", includes: ['*.jar'])
// OR below
// pmd 'org.aspectj:aspectjtools:1.9.4'
}
Using toolVersion doesn't work anymore then. In order to use a different PMD version, you just need to update the version in the dependency then.
Btw. I can't reproduce your problem with pmdAux - if the dependency is added to pmdAux, PMD is executed. However, it might not run correctly, as probably the same happens: the automatically calculated auxiliary classpath is thrown away and only your declared dependencies are used. That might result in false-positives/false-negatives due to type resolution not working correctly.
I have a gradle project with several modules in it. In the main module I have id "io.spring.dependency-management" plugin. In the adapters module I have dependency on the main one implementation project(":main") with runtimeOnly 'io.r2dbc:r2dbc-postgresql in dependency block, which pulls 0.8.12.RELEASE version of the r2dc-postgresql driver.
Now I want to use 0.8.13.RELEASE verision of the driver, so I simply added runtimeOnly 'io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE to the dependency declaration, but now I have two versions of this library in external libraries section (0.8.12.RELEASE and 0.8.13.RELEASE), but ./gradlew adapters:dependencies displays only 0.8.13.RELEASE version.
How to find out where 0.8.12.RELEASE is coming from now and remove it?
I tried
exlude(group = 'io.r2dbc', module = 'r2dbc-postgresql')
but it didn't work
have you had a look at e.g.:
https://docs.gradle.org/current/userguide/resolution_rules.html
or
How to exclude library from all dependencies in Kotlin DSL build.gradle?
or
What does this "all*.exclude" means in Gradle transitive dependency?
When calling gradle idea, external dependencies are ordered first in the class path relatively to local Jar inclusions. As such :
dependencies {
compile fileTree(dir: 'libs', include:['*.jar'])
compile group: 'foo', name:'bar', version:'1.0.0'
}
will include my local jars last. This is a problem in my project as these jars' purpose is to partially overwrite the external library.
The same behavior is observed when specifying the repository as a source of dependencies using flatDir and loading the jar without fileTree. It is put last in the classpath.
I have found several mentions of the problem when researching, such as https://discuss.gradle.org/t/gradle-messes-up-the-classpath-order-in-generated-projects-when-there-are-mixed-dependency-types/13130, but no workarounds.
I suppose these exist, gradle being very customisable, but being very new to it my attempts to make one fail. How to proceed?
I'm not using IntelliJ on a regular basis but tried it in the context of this question and my impression is that gradle's idea plugin and IntelliJ's gradle plugin don't go well together. That is you should either use the idea gradle plugin and import as plain Java project or import as gradle project using IntelliJ's gradle plugin. Main reason is that the idea plugin and the IntelliJ plugin are generating slightly different iml-files (those files are holding the project dependencies - amongst others) which leads to lot of confusion when using both plugins together. As you specifically asked for the gradle idea plugin, I used this plugin and imported into IntelliJ as plain java project.
But to answer your question I found no evidence that the order of libraries on the classpath differs from the order as declared in the dependencies section of the gradle file, when using a flatDir repo. When using compile fileTree(dir: 'libs', include:['*.jar']) the order was actually broken as described in your question. That is, you should stick to using a flatDir repo.
I'm using gradle 4.9 and IntelliJ 2018.2.
This is my gradle file
apply plugin: 'java'
apply plugin: 'idea'
repositories {
jcenter()
flatDir {
dirs 'libs'
}
}
dependencies {
compile 'zzz:zzz-0.0.0'
compile 'aaa:aaa-0.0.0'
compile 'com.google.guava:guava:24.0-jre'
compile group: 'javax.websocket', name: 'javax.websocket-api', version: '1.1'
}
task wrapper(type: Wrapper) {
gradleVersion = '4.9'
distributionUrl = "http://services.gradle.org/distributions/gradle-${gradleVersion}-bin.zip"
}
In my libs folder there are two jars aaa-0.0.0.jar and zzz-0.0.0.jar both are copies of guava-24.0-jre.jar. That is all guava classes are present in both jars as well. As zzz:zzz-0.0.0 is the first dependency in the gradle file, the expectation would be that guava classes are being loaded from zzz-0.0.0.jar instead of guava-24.0-jre.jar or aaa-0.0.0.jar. I used the following main class to test this:
package test;
import com.google.common.math.LongMath;
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(LongMath.class.getProtectionDomain().getCodeSource().getLocation().toURI());
}
}
And the output when running it from IntelliJ is
file:/C:/ws/gradle-idea-test/libs/zzz-0.0.0.jar
That is the com.google.common.math.LongMath class is indeed being loaded from the local libs/zzz-0.0.0.jar instead of the guava-24.0-jre.jar.
I noticed that the list of external dependencies in IntelliJ doesn't show the local libraries. And even more confusing the libraries are ordered alphabetically and don't reflect the actual order on the classpath which might be quite confusing:
To get the actual order of elements on the classpath you will have to look in the module dependencies section in the module settings ("Open Module Settings" > "Project" > "Modules" > "Dependencies Tab") which looks like this:
As you can see the dependencies are listed in correct order and include the local libraries as well. The order of libs in this dialog is basically the same as in the generated iml-file.
When using the IntelliJ gradle plugin instead of gradle's idea plugin, IntelliJ basically behaved the same way but the generated iml-file looked different and the external libraries were displayed in a different format. But there was no difference regarding the classpath order.
I am trying to get Gradle to select different dependencies in my multiproject build based on whether I am building for desktop or for Android. I have a common subproject (a library) I am trying to reuse. However, I cannot get Gradle to correctly switch dependency configurations.
My main settings.gradle simply includes all the dependencies:
// /settings.gradle
rootProject.name = 'myProject'
include 'androidUI'
include 'reusableLibrary'
include 'desktopUI'
Now both androidUI and desktopUI specify reusableLibrary as a dependency:
// /androidUI/build.gradle and /desktopUI/build.gradle
apply plugin: 'java'
dependencies {
compile project(path: ':reusableLibrary', configuration: 'desktop')
}
reusableLibrary itself specifies two configurations, because its dependencies are different whether it's building on desktop or Android:
// /reusableLibrary/build.gradle
apply plugin: 'java'
configurations {
desktop {
extendsFrom compile
}
android {
extendsFrom compile
}
}
dependencies {
// Just examples, the real list is longer.
// The point is that h2database is only included on desktop,
// and ormlite is only included on Android.
android 'com.j256.ormlite:ormlite-jdbc:5.0'
desktop 'com.h2database:h2:1.4.192'
}
This looks fine to me. But when I compile either desktopUI or androidUI, I can see that although the dependencies of reusableLibrary are being included on the classpath in the manner I desire, the actual JAR provided by reusableLibrary itself is not included. This of course causes the build to fail. I suspect I'm not setting up reusableLibrary correctly; I'm not clear on what the configurations {} blocks do.
Why aren't the compiled items in reusableLibrary being included on the classpaths of the UI projects? And what is the canonical way to include platform-specific dependencies in this manner?
The original configuration is pretty close to right. The key is to understand this dependency graph from the Gradle Java plugin's documentation:
This is a visualization of the Java plugin's various dependency configurations, which is Gradle-ese for "list of dependencies." When you add compile lines to a dependencies {...} block, you're adding Dependency elements to the compile dependency list.
The default dependency configuration is special; it is the one included by a compile project("path") line unless a different one is chosen with the configuration: argument. This means that when you build the library, the runtime dependency list (which includes the compiled jar from the library itself) is added to the classpath of the client project.
The original configuration creates two new nodes, desktop and android in this graph, and couples them both to compile by using extendsFrom. They are not otherwise connected to the graph! Now the problem with the original configuration is apparent: by switching the upstream project to either of these, it is missing the compiled code from runtime. This explains the classpath omission.
The solution is a bit more subtle than just aiming desktop and android at runtime. In order to ensure that everything is correctly decoupled when we add tests, we need one extra layer of dependency configurations to keep testCompile from indirectly depending on runtime. Additionally, the library's source code itself may need things on its classpath just to typecheck; we can use compileOnly for this. The end solution looks like this:
configurations {
desktopCompile
androidCompile
compileOnly.extendsFrom desktopCompile
testCompile.extendsFrom desktopCompile // Assuming tests run on the desktop
desktop {
extendsFrom desktopCompile
extendsFrom runtime
}
android {
extendsFrom androidCompile
extendsFrom runtime
}
}
dependencies {
androidCompile "some.android:dependency"
desktopCompile "other.desktop:dependency"
}
I am attempting to compile several WAR files, all that depend on a common JAR module. In my Gradle build however, I cannot seem to get a 'Provided' like dependency to work with the Java plugin.
My compile looks like this:
apply plugin: 'java'
configurations{
providedCompile
}
dependencies {
compile module("org.springframework.amqp:spring-amqp:${springAmqpVersion}")
compile module("org.slf4j:slf4j-api:${slf4jVersion}")
compile module("org.slf4j:slf4j-ext:${slf4jVersion}")
providedCompile "javax.servlet:servlet-api:${servletApiVersion}"
runtime module("org.slf4j:jcl-over-slf4j:${slf4jVersion}")
runtime module("org.slf4j:jul-to-slf4j:${slf4jVersion}")
runtime module("org.slf4j:log4j-over-slf4j:${slf4jVersion}")
sourceArchives module("org.springframework.amqp:spring-amqp:${springAmqpVersion}:sources")
sourceArchives module("javax.servlet:servlet-api:${servletApiVersion}:sources")
}
sourceSets {
main { compileClasspath += configurations.providedCompile }
}
However, that last bit is where it gets an exception. I have tried adding the servlet-api (Provided by Tomcat) to the configuration after the runtime dependencies would extend it, or simply putting it in as a compile module, then removing it from runtime dependencies later.
I've attempted several different ways of modifying the dependencies, with my closest results being:
newRuntime = configurations.runtime.minus(configurations.providedCompile)
configurations.runtime = newRuntime
This last bit however, will generate the variable newRuntime with the proper dependencies, however when I tried to reassign the variable back to the runtime configuration, it throws a "Cannot find property exception"
I found a lot of discussion of this exact problem on Gradle's bug tracking:Gradle-784
However the main lead from that is from Spring who uses Maven with their gradle builds, which I am unfamiliar with.
The most promising link I found here on SO, but unfortunately I could not get the examples to work as well: SO Provided Question
Of note for the Stack Overflow question the line that showed most promise:
//Include provided for compilation
sourceSets.main.compileClasspath += configurations.provided
This line does not give an error like other attempts, however it appears that the providedCompile (My version of provided) dependency is not actually put on the compile classpath, as there is a classpath error when compilation is attempted.
I'm not 100% following your message but providedCompile is only allowed for 'war' plugin.
apply plugin: 'war'
dependencies {
// others go here
providedCompile "javax.servlet:javax.servlet-api:${servletVersion}"
}
During 'war' step the servlet jar is not included.
You have added a providedCompile configuration, but you aren't doing anything with it. Hence it won't make it on any class path. To put the configuration on the main compile class path, you can do:
sourceSets.main.compileClasspath += configurations.providedCompile
Likewise, to put it on the test compile class path:
sourceSets.test.compileClasspath += configurations.providedCompile
You can use compile scope inside 'jar' modules and providedCompile inside 'war' module.
War's providedCompile scope will override jar's compile scope.