Gradle won't resolve dependency (Maven will) - java

My project has dependencies configured through gradle. I would like to add the following dependency:
compile group: 'org.restlet.jse', name: 'org.restlet.ext.apispark', version: '2.3.1'
Which can be found in the following repository (which I have added to my build.gradle):
maven {
url "http://maven.restlet.org"
}
However when I do that I get the following error:
Could not find org.restlet.jse:org.restlet.lib.swagger-models:1.5.0-SNAPSHOT.
http://maven.restlet.org/org/restlet/jse/org.restlet.lib.swagger-models/1.5.0-SNAPSHOT/maven-metadata.xml
http://maven.restlet.org/org/restlet/jse/org.restlet.lib.swagger-models/1.5.0-SNAPSHOT/org.restlet.lib.swagger-models-1.5.0-null-null.pom
http://maven.restlet.org/org/restlet/jse/org.restlet.lib.swagger-models/1.5.0-SNAPSHOT/org.restlet.lib.swagger-models-1.5.0-null-null.jar
Required by: org.restlet.jse:org.restlet.ext.apispark:2.3.1
I can see that the jar is in fact in the repository however Gradle is not looking for it in the right location for reasons unknown to me. Why is it not using the version in the filename but rather 1.5.0-null-null.
I have made a made a Maven project with the same dependency defined in the pom.xml which works.
Link to working pom.xml that has same dependency
How can this issue be resolved? I'm at this point also interesting in more manual solutions :) Thank you.

Diagnosis
It seems to be related to snapshot "uniqueness". For information on Maven repositories, snapshots artifacts can be deployed "unique" or "non-unique".
Unique snapshots: Each time you deploy a snapshot, it is tagged with a timestamp and a buildNumber, these timestamp and buildNumber are written in the maven-metadata.xml file and they are appended to its name that ends up like: artifactName-version-timestamp-buildNumber.jar.
Non-unique snapshots: Each time you deploy a snapshot it overwrites the previous version, his name ends up like: artifactName-version.jar.
It is recommended to use unique snapshot as one can refer precisely to one version of the artifact if needed.
The problem is that "http://maven.restlet.org" seems to use non-unique snapshots and sadly, gradle seems to have problems to deal with non-unique snapshots: https://issues.gradle.org/browse/GRADLE-3164.
If you look at http://maven.restlet.com/org/restlet/jse/org.restlet.lib.org.restlet.lib.swagger-models/1.5.0-SNAPSHOT/maven-metadata.xml you can clearly see null in timestamp and buildNumber tags:
<metadata>
[...]
<versioning>
<snapshot>
<timestamp>null</timestamp>
<buildNumber>null</buildNumber>
</snapshot>
<lastUpdated>null</lastUpdated>
</versioning>
</metadata>
I think that's where the "null-null" comes from.
Solution 1 - flatDir
To deal with it you can manually download the artifact, put it in a directory, for example "lib" and create a flatDir repository:
repositories {
[...]
flatDir {
dirs 'lib'
}
[...]
}
It's not an ideal solution, but it works.
Solution 2 - jcenter repository
Suggested by Opal
Add the jcenter repository that contains your missing dependency and that Gradle handles well.
Since Gradle 1.7 you can simply define it with:
repositories {
[...]
jcenter()
[...]
}

It seems that you need other repositories to download all the dependencies. Probably maven handle this transparently. The following script downloads all dependencies successfully when cp task is run:
apply plugin: 'java'
configurations {
lol
}
repositories {
jcenter()
mavenCentral()
maven {
url "http://maven.restlet.org"
}
maven {
url "https://repository.mulesoft.org/nexus/content/repositories/public/"
}
}
dependencies {
lol group: 'org.restlet.jse', name: 'org.restlet.ext.apispark', version: '2.3.1'
}
task cp(type: Copy) {
from configurations.lol
into 'deps'
}

Related

Gradle find wrong maven repository url in eclipse

this is my build.gradle
repositories {
mavenCentral()
maven{url 'http://example.com/repository/maven-public/'}
}
dependencies {
compile group: 'com.example', name: 'example-commlib', version: '1.0'
}
and the link http://example.com/repository/maven-public/ is build from Nexus Repository Manager which can accessable.
and when I click Refresh Gradle Project in eclipse.
I can see the link is point to
https://repo.maven.apache.org/..../example-commlib-1.0.pom
I think the right url is
http://example.com/repository/maven-public/.../example-commlib-1.0.pom
I've check the gradle setting and maven setting in eclipse. It seems fine.
So what's the problem?
Do you have other dependencies on this project? It is possible that the "pom.xml" file of one of the packages you are pulling references example-commlib as a dependency and has the Apache Maven URL hardcoded, and resolves the URL beforehand. You can use gradle dependencies to show the dependency tree and find which version is affected. The answers in this post have suggestions on how to force a specific dependency as well: How can I force Gradle to set the same version for two dependencies?

using gradle plugin from flatDir source

How to amend Gradle plugins {} management repository for custom plugins? is not duplicated in this post, because it does not cover use of flatDir.
Question
How do I use a Gradle plugin defined in a local JAR, using the new plugin {} semantics, instead of the deprecated apply() semantics?
Current Status
Not having any resolution, after posting the question and searching at considerable length, I filed an issue, wondering whether this use, which ought to be common and straightforward, is unsupported, either by design or oversight, within Gradle's revised plugin semantics.
Unfortunately, my report was closed, with no useful information provided.
I requested clarification in a new issue, but am still waiting.
I am frustrated, having expected that the community would be interested in at least discussing this problem.
If you can contribute information, please do so.
First Update
Following the clarification about the new style for configuring plugin sources, I updated my settings.gradle file to open with the following block. However, I regret that I see no improvement by this change alone. (For the plugin id field referenced in the build.gradle file, I have tried both the global ID published in the JAR metadata, and the basename of the JAR fie. Both fail equally.)
pluginManagement {
repositories {
gradlePluginPortal()
jcenter()
flatDir {
dirs 'lib`'
}
}
}
The documentation explains how to use custom repositories, but appears to overlook the case of a trivial flat directory.
Second Update
I get some improvement if I add a version number to the JAR file and to the corresponding statement in the plugins {} block. In this case, the message becomes:
Plugin [id: 'plugin-id', version: '1.0.0'] was not found in any of the following sources:
- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (could not resolve plugin artifact 'plugin-id:plugin-id.gradle.plugin:1.0.0')
Searched in the following repositories:
Gradle Central Plugin Repository
BintrayJCenter
flatDir(/absolute/path/to/lib)
In this case, the directory is added to the list of sources searched.
It is strange that the .gradle.plugin suffix is being appended to my ID in the printed artifact. It is also strange that adding the version number to what is being searched for affects the list of places being searched.
So my project still cannot build. I appreciate any further help.
Original Background
I placed a JAR file containing a custom plugin definition in the lib directory of a project. With the build.gradle build file as below, the build runs successfully.
buildscript {
repositories {
flatDir {
dirs 'lib'
}
}
}
apply plugin: 'plugin-id'
However, the apply() semantics are deprecated, favoring a plugins {} block, so I tried updating the build file as below.
plugins {
id 'plugin-id'
}
repositories {
flatDir {
dirs 'lib'
}
}
I understand that the plugins {} contents can draw from the repositories {} definitions.
However, the change creates a failure:
* What went wrong:
Plugin [id: 'plugin-id'] was not found in any of the following sources:
- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (plugin dependency must include a version number for this source)
Keeping the plugin {} block but moving the repositories {} block back into a leading buildscript {} block does not resolve the error. That is, the error persists even if I revert to the earlier version only replacing the apply() statement with the plugin {} block.
Finally, it has no effect to add to the repositories {} block a dependencies { classpath: ':jarname' } block, which some sources suggest is necessary, though I don't know why it would be.
This works. Tested with gradle 6.3.
build.gradle:
plugins {
id 'plugin-id'
}
settings.gradle:
pluginManagement {
buildscript {
repositories {
flatDir {
dirs '/plugin-folder/build/libs'
}
}
dependencies {
classpath ':plugin-jar:0.0.1'
}
}
}
Update: I just found out today that it is possible to have your plugin jar resolved without using the dependencies block above. In that case you should name your plugin jar as [plugin-id].gradle.plugin[-version].jar. Note that the [-version] part is optional and plugin-id.gradle.plugin.jar will also work.
NB: Flat dir repositories are discouraged and local maven repo folder should be used instead. Especially in the case when you want to override locally an artifact which exists on a remote repo. See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver. It seems impossible to fully move away from maven in favour of gradle, considering that installing local artifacts in a maven repo folder is not supported by gradle itself.

gradle can't resolve nexus dependency

I have a dependency I'd like to include from a local nexus. I've seen several related problems that all say to do something like
apply plugin: "java"
apply plugin: "maven"
repositories {
maven {
url "http://my.url.com/"
}
}
dependencies {
compile "name:id:version"
}
I can access the nexus fine via web but when I try the above, I end up with a error message
Could not resolve: name:id:version
Any help would be greatly appreciated.
I found my problem. There were transitive dependencies I didn't catch as I was initially building from Eclipse without the --stacktrace option. I modified the build script such that
compile("name:id:version") {
exclude group: "another-name", module: "its-module"
// other dependencies to exclude ...
}
If by local repository you mean your local computer repository, then to ask Gradle to lookup dependencies from the local maven repository you should explicitly tell him to do so like this:
repositories {
mavenLocal()
}
Gradle is not like maven and is not using the local repository of the maven to cache downloaded artifacts. From the Gradle points of view, the local maven repository is also like other repositories.

Including Java library built with Gradle throws NoClassDefFoundError

I am writing a Java library and I would like to build the library with Gradle and then test it from a local test project.
I would prefer using Gradle 3.3 for my objective.
The library should be built for Java5 and higher.
So far my build.gradle looks like this:
plugins {
id 'jvm-component'
id 'java-lang'
}
repositories {
mavenCentral()
}
model {
components {
main(JvmLibrarySpec) {
sources {
java {
dependencies {
module 'commons-codec:commons-codec:1.10'
module 'org.apache.httpcomponents:httpcore:4.4.6'
module 'org.apache.httpcomponents:httpclient:4.5.3'
}
}
}
api {
exports 'io.simplepush'
}
targetPlatform 'java5'
}
}
}
The source code of the library is located in src/main/java/io/simplepush/Notification.java and depends on the dependencies stated in the build.gradle file.
Building the library with ./gradlew build works fine and generates build/jars/main/jar/main.jar.
However when I run a test project from IntelliJ (after including main.jar into the test project), I get the following runtime error:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/HttpEntity.
It seems like the test project does not know about the runtime dependencies needed by my library.
I am not sure on what is the correct way to tell the test project about the dependencies of my library.
I do not want a fat jar which includes all dependencies.
Listing all dependencies in the test project itself is also not an option.
Preferably I want the library itself to tell the test project about which dependencies it needs.
The library jar which you have created does not contain any dependency information which the IDE/Gradle can then resolve to be able to compile/run the test project. I see that you are using the maven central repository so what you need to do is to publish your library to your local maven repository and in the test project just add a dependency information (no just plain jar file).
So in both library and test project build.gradle add a maven local repository config.
repositories {
mavenLocal()
mavenCentral()
}
And now you need to publish the library to local repository. As you are using the gradle 3.3 you can use the Maven Publishing.
So in the library build.gradle add a maven publishing information.
publishing {
publications {
maven(MavenPublication) {
groupId 'io.simplepush'
artifactId 'project1-sample'
version '1.1'
from components.java
}
}
}
Gradle “maven-publish” plugin makes this easy to publish to local repository automatically creating a PublishToMavenLocal task.
So you can just run
gradle publishToMavenLocal
Which will publish your library with all the dependency information into local maven repository.
And then you just need to add a library information to you test projects build.gradle
dependencies {
// other dependencies .....
module 'io.simplepush:project1-sample:1.1'
}
I solved it by changing several things.
Thanks to #Babl for pointing me in the right direction.
My new library build.gradle looks like this:
plugins {
id 'java'
id 'maven-publish'
}
sourceCompatibility = 1.5
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile 'commons-codec:commons-codec:1.10'
compile 'org.apache.httpcomponents:httpcore:4.4.6'
compile 'org.apache.httpcomponents:httpclient:4.5.3'
}
publishing {
publications {
maven(MavenPublication) {
groupId 'io.simplepush'
artifactId 'project1-sample'
version '1.1'
from components.java
}
}
}
Now I can push the library to the local maven repository with ./gradlew publishToMavenLocal.
The build.gradle of the test project uses the application plugin and defines a main class (which is Hello in my case). Then I can run ./gradlew installDist to generate an executable file (see Application plugin docs) which puts all dependencies in the classpath and runs just fine.
group 'com.test'
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'application'
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile 'io.simplepush:project1-sample:1.1'
}
mainClassName = "Hello"
This specify what repositories to check to fetch the dependencies from
repositories {
mavenCentral()
}
Therefore, anything that is in the dependecies{} will be fetched from those above.
If the test project is not coupled with the library project, (#RaGe example) new test project needs to know where to take the dependency from - you need to publish it, using preferred method.
After that, your new test project needs to specify the library with the preferred configuration (compile...runtime etc) in the build.gradle dependencies{}
After that depending on IDE you need to refresh the classpath and download the dependency from the specified before repository, the transitive dependencies specified in the library dependency (in this case) will get fetched from test projects repositories{}
Library build.gradle
repositories {
mavenCentral()
}
dependencies {
module 'commons-codec:commons-codec:1.10'
module 'org.apache.httpcomponents:httpcore:4.4.6'
module 'org.apache.httpcomponents:httpclient:4.5.3'
}
test project build.gradle
repositories {
mavenCentral() repository to fetch transitives
mavenLocal() or any other repo that you published the library to
}
dependencies {
pref-conf librarygroup:name:version
}
You can use idea or eclipse plugin in gradle for gradle idea or gradle eclipseClasspath tasks to refresh it with your freshly added dependencies.
With this solution, you should not need to pack the transitive dependencies within the library,
PS. I am just confused after you said you want executable jar.

Make Gradle use Maven local repository for downloading artifacts

I know I can configure Gradle to use local Maven repository
repositories {
mavenLocal()
mavenCentral()
}
Can I configure Gradle to download into Local (maven) repository? (So that Maven would also be able to use those jars)
ref Gradle configuration to use maven local repository
A solution was given in the gradle forums:
https://discuss.gradle.org/t/need-a-gradle-task-to-copy-all-dependencies-to-a-local-maven-repo/13397/2
using this gradle plugin: https://github.com/ysb33r/ivypot-gradle-plugin
you can call a new tasg
gradle syncRemoteRepositories
which will download all dependencies to a local Ivy repository (which is the same library Maven uses). The folder you point to with
syncRemoteRepositories {
repoRoot '/path/to/repo'
}
will contain the dependencies. I would suggest first trying out with a different local path than your M2_HOME, because I saw some warning about the Ivy repository structure having changed between Maven versions.
It should be as simple as
apply plugin: 'maven'
apply plugin: 'java'
dependencies {
mavenLocal()
}
And
gradle install
More info here

Categories