Same interface in 2 different dependency issue - java

I have conflict problem with dependencies.
My project has two dependencies like this:
dependencies {
provided group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
compile files('path/to/ABC.jar')
}
ABC.jar has its own dependency to javax.servlet:servlet-api:
dependencies {
provided group: 'javax.servlet', name: 'servlet-api', version: '2.5'
}
Here is the problem I am dealing with; I need to use ServletContext interface which is provided by both servlet-api libraries and the compiler uses wrong one.
Gradle auto-resolves version conflicts as described here.
But in my case it doesn't help, because it only works when a dependency has two different versions. In this case; although it's a newer version issue, the name has changed from javax.servlet:servlet-api to javax.servlet:javax.servlet-api. So gradle doesn't auto-resolve this conflict, because it doesn't seem to be a version issue.
The thing I tried was using excluding transitive dependency as described here.
compile files('path/to/ABC.jar') {
exclude group: 'javax.servlet'
}
But it didn't work, it seems exclude doesn't work on local 'jar' files.
Now, I don't know what else to do.
How can I exclude a dependency of a dependency which is added as a local file?
(If the first question doesn't have any answer yet) How can I say to the compiler to use the correct ServletContext interface?

compile files('path/to/ABC.jar') is a file dependency, a file dependency does not have any dependency information, so it does not introduce transitive dependencies. If this ABC.jar is a "fat" jar that has the dependency-classes included in the JAR, it is not suited for usage in something like Gradle, Maven or Ant/Ivy that is supposed to handle the dependencies. You would have to use a proper "thin" version of the dependency with the dependencies properly declared, or you need to "repackage" that JAR in your build script to exclude the dependency classes you don't want to pull in. No dependency management can do this for you.
You can execute gradlew dependencyInsight --configuration runtime --dependency javax.servlet:servlet-api or gradlew dependencies --configuration runtime to find out where the dependency really comes from.
Actually your example should not even compile if I see it correctly, because it should most probably be
compile files('path/to/ABC.jar'), {
exclude group: 'javax.servlet'
}
or
compile(files('path/to/ABC.jar')) {
exclude group: 'javax.servlet'
}
But as I said, with a local file dependency there are no transitive dependencies, so an exclude does not make sense at all anyway.
To make the Gradle version conflict magic work, you can simply tell Gradle that those libraries are actually the same library just with different coordinates by using a module replacement like
dependencies {
modules {
module('javax.servlet:servlet-api') {
replacedBy 'javax.servlet:javax.servlet-api'
}
}
}
Then Gradle sees them as the same library and can do its version conflict resolution magic. Whether the library that needs the old version still works with the new version is a different topic that you have to check and / or try yourself. This like always depends on whether the new version is backwards compatible to the old version.

I have no way to test this now, but I believe your syntax is wrong. I have some examples here that look different, in your case it would be:
compile(files('path/to/ABC.jar')) {
exclude group: 'javax.servlet'
}
As I say, I cannot test it now, check if it helps and give a comment.

Related

IntelliJ with gradle gives inconsistency in compilation

I'm writing Minecraft Plugin using IntelliJ IDEA Ultimate with gradle. I have added dependency org.spigotmc:spigot-api:1.13.2-R0.1-SNAPSHOT as compileOnly. During development, I noticed that gradle compiles my code in different way than IntelliJ does. For example, IntelliJ was unable to accept addPassenger on Boat, but gradle compiled it. In the opposite way, if I changed it into setPassenger, IntelliJ didn't mark it as error, but gradle failed to compile. I tried to invalidate caches, reimport, clean, even remove %userprofile%\.gradle directory, nothing helped. As a POC I changed compileOnly to compile and it worked well, IntelliJ and gradle compilation results were consistent. What's the reason?
Ok, I found the solution (and forgot about this question).
I had been using multiple dependencies, and one load another with older version that I loaded implicitly in my build.gradle. However, they weren't exactly the same dependencies, but parallel ones. So gradle could not choose higher version of one dependency. Solution was to exclude this one explicitly loaded dependency and everything worked well.
Before:
dependencies {
compileOnly 'com.sk89q.worldedit:worldedit-bukkit:7.0.1'
compileOnly group: 'org.spigotmc', name:'spigot-api', version: '1.15.1-R0.1-SNAPSHOT'
}
After:
dependencies {
compileOnly('com.sk89q.worldedit:worldedit-bukkit:7.0.1') {
exclude `org.bukkit:bukkit:1.15.1-R0.1-SNAPSHOT`
}
compileOnly group: 'org.spigotmc', name:'spigot-api', version: '1.15.1-R0.1-SNAPSHOT'
}

Intellij not including gradle dependency on classpath when running an app

IntelliJ is not including by logback-classic dependency on classpath when running the application from IDE (it is kotlin application, but it shouldn't matter). My gradle build contains a line:
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.+'
Dependency is correctly listed under "External Libraries" in IntelliJ.
When I try to manually reference a class that the dependency provides in the source code, compiler doesn't complain and it compiles the code successfully.
However, when I run the application I get ClassNotFoundException.
//This import is provided by logback-classic library
import org.slf4j.impl.StaticLoggerBinder
...
// This compiles successfully, but will trigger ClassNotFoundException when run
val singleton = StaticLoggerBinder.getSingleton()
I included the code to list out the runtime classpath:
val cl = ClassLoader.getSystemClassLoader()
val urls = (cl as URLClassLoader).urLs
for (url in urls) {
System.out.println(url.file)
}
And the output, when run from IDE, doesn't include logback-classic. Sample output:
...
/Users/knesek/.gradle/caches/modules-2/files-2.1/commons-httpclient/commons-httpclient/3.1/964cd74171f427720480efdec40a7c7f6e58426a/commons-httpclient-3.1.jar
/Users/knesek/.gradle/caches/modules-2/files-2.1/com.fasterxml.jackson.core/jackson-databind/2.8.8/bf88c7b27e95cbadce4e7c316a56c3efffda8026/jackson-databind-2.8.8.jar
/Users/knesek/.gradle/caches/modules-2/files-2.1/com.fasterxml.jackson.module/jackson-module-jaxb-annotations/2.8.8/e2e95efc46d45be4b429b704efbb1d4b89721d3a/jackson-module-jaxb-annotations-2.8.8.jar
/Users/knesek/.gradle/caches/modules-2/files-2.1/com.sun.mail/javax.mail/1.5.6/ab5daef2f881c42c8e280cbe918ec4d7fdfd7efe/javax.mail-1.5.6.jar
/Users/knesek/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-core/1.1.11/88b8df40340eed549fb07e2613879bf6b006704d/logback-core-1.1.11.jar
/Users/knesek/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.1/98e484e67f913e934559f7f55f0c94be5593f03c/kotlin-stdlib-1.1.1.jar
/Users/knesek/.gradle/caches/modules-2/files-2.1/org.springframework/spring-beans/4.3.9.RELEASE/daa5abf3779c8cad1a2910e1ea08e4272489d8ae/spring-beans-4.3.9.RELEASE.jar
...
Fascinatingly, logback-core is in there while logback-classic is not (and logback-core is a transitive dependency of logback-classic).
I tried invalidating InteliJ cahces, rebuilding and restarting InteliJ. Compling from gradle and running the jar works fine. Any suggestions?
It seems this a bug in InteliJ for which I'll file a bug report. Including this answer with a workaround here for anyone who might encounter similar issue.
It seems that when there is a certain combinations of dependencies present on the classpath, then when you use gradle dependency like this
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.+'
it will not get included when run from the IDE. But if you include it like this:
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.+'
then it works. First example did work for a while, until I included more dependencies.

Exclude Package From Gradle Dependency

I'm experiencing an issue where multiple versions of the same class are showing up in my classpath. The class in question is javax.ws.rs.core.UriBuilder. The version I want to use is brought in by javax.ws.rs:javax.ws.rs-api:2.0.1. However, we also use the Jira rest client library which has a dependency on the older version of jersey (com.sun.jersey:jersey-core) which has included the java.ws packages bundled in it's jar.
Here is an example snippet from the build file:
dependencies {
compile 'com.atlassian.jira:jira-rest-java-client-core:2.0.0-m31'
compile 'javax.ws.rs:javax.ws.rs-api:2.0.1'
compile 'org.glassfish.jersey.core:jersey-client:2.17'
}
I can't remove com.sun.jersey:jersey-core as it uses different package name from the new version and would cause class def not found exceptions in the Jira client.
As far as I can tell, my options at this point are:
Revert to using Jersey 1.x and it's implementation of jsr311
Somehow have gradle exclude the javax.ws package from the old jersey client.
I'd like to keep using the newer version of jersey so #2 would be my ideal solution but I'm not sure if it's even possible. Does anyone know how to go about this? If that's not possible, I'm open to other suggestions.
You can exclude an transitive dependency module like this:
compile ('org.glassfish.jersey.core:jersey-client:2.17') {
exclude group: 'javax.ws.rs'
exclude module: 'javax.ws.rs-api'
}
ref: 50.4.7 here
I found out that com.sun.jersey:jersey-core:1.19 doesn't bundle the javax.ws.rs class files and instead lists them as a compile-time dependency. Adding this snippet to my build.gradle fixed the issue.
configurations.all {
resolutionStrategy {
// For a version that doesn't package javax.ws
force 'com.sun.jersey:jersey-core:1.19'
}
}
exclude the group and module as below.
Ex :
implementation('org.apache.httpcomponents:httpclient:4.5.13') {
exclude group: 'commons-codec', module: 'commons-codec'
}

This dependency gives me two versions of one jar. How do I fix this?

I'm using Gradle for my project. One of the dependencies I have specified in my build.gradle is
compile 'org.glassfish.jersey.media:jersey-media-moxy:2.0'
This works fine on a normal Java application, however when I try to build it on Android I get:
When looking at which libraries are referenced, it's clear that there's both javax.inject-2.3.0-b05.jar and javax.inject-1.jar, which I found are added by the dependency above. I'm guessing that this 'duplicate' jar is what causes the build error.
How do I go around this? Why does the dependency include two of the same jar? Is there a way to either make the Android version build with these two jars or to remove one of these jars?
It appears that you have a dependency tree akin
project
|--- org.glassfish.jersey.media:jersey-media-moxy:2.0
| \--- *:javax.inject:1
\--- *:javax.inject:2.3.0-b05
Where * is the group, which I suspect may be different from those two.
Try getting an idea of how your dependencies are being grabbed by using the dependency task
gradle dependency
Should you need to exclude a dependency enter it in the tag, similar to the below example
compile('org.hibernate:hibernate:3.1') {
//excluding a particular transitive dependency:
exclude module: 'cglib' //by artifact name
exclude group: 'org.jmock' //by group
exclude group: 'org.unwanted', module: 'iAmBuggy' //by both name and group
}
Normally gradle will only include 1 jar per dependency. If different version found for the same depedencies, the newer version will be used.
However, in your case, these 2 jars are dependencies with different group names:
'javax.inject:javax.inject:1'
'org.glassfish.hk2.external:javax.inject:2.3.0-b05'
That's why gradle included both as they are treated as different dependencies.
'javax.inject:javax.inject:1' is very old, I think you should exclude it like what Niels Bech Nielsen said.
To find out where is this dependency come from , you can use command:
gradle -q dependencyInsight --dependency inject

Gradle: excluding a jar from runtime dependencies

I need to exclude a jar from runtime dependency via Gradle.
I am getting this error:
Caused by: java.lang.IllegalStateException: Conflicting persistence unit definitions for name 'ldb-jpa': file:/D:/EricFrancis/shared/build/libs/shared.jar, file:/D:/EricFrancis/shared/build/resources/main
I'm trying to exclude the jar.
How do I tell gradle to do this?
Without more information (Gradle version, relevant parts of build script, etc.), it's hard to say. But since this isn't a Maven or Ivy dependency, I'd consider not adding it in the first place.
It turns out that I did not understand how configurations worked.
I was able to exclude the jar via:
configurations {
testRuntime {
exclude module: 'share'
}
testCompile {
exclude module: 'share'
}
}

Categories

Resources