Gradle does not use the Maven Local Repository for a new dependency
Gradlebuild.gradleGradle Problem Overview
I have Maven with M2_HOME
defined to /Users/manuelj/apache/maven/3.2.5
I have the settings.xml
file, located on /Users/manuelj/apache/maven/3.2.5/conf/settings.xml
where I have the following declared:
<localRepository>/Users/manuelj/apache/maven/repository</localRepository>
Until here with Maven all works fine. Any new dependency goes there.
I have a project based with Gradle, among many things in my build.gradle, exists the following:
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'eclipse'
apply plugin: 'application'
version = '1.0.0'
sourceCompatibility = '1.8'
repositories {
mavenLocal()
mavenCentral()
}
… more
Until here, all works fine too. Code compile, executes well.
My confusion is the following.
According with my understanding is that Gradle's mavenLocal()
should use the same path than <localRepository>
defined on Maven's settings.xml
file.
Now confirming that in the Maven local repository exists some dependencies already downloaded.
When I execute for example gradle build, I did realize that
- If a dependency already exists from the Maven Local Repository, it is used from there.
- If a dependency does not exist from the Maven Local Repository Gradle download the new dependency to:
/Users/manuelj/.gradle/caches/modules-2/files-2.1
I want that the new dependency go directly to the same Maven Local Repository.
Therefore, what extra configuration is need it?
Gradle Solutions
Solution 1 - Gradle
Resolving Dependencies From Local Maven Repository
Gradle is able to resolve artifacts stored in the local Maven repository (usually ~/.m2/repository
) via mavenLocal().
According to the documentation, mavenLocal()
is resolved like this:
> Gradle uses the same logic as Maven to identify the location of your local Maven cache. If a local repository location is defined in a settings.xml
, this location will be used. The settings.xml
in USER_HOME/.m2
takes precedence over the settings.xml
in M2_HOME/conf
. If no settings.xml
is available, Gradle uses the default location USER_HOME/.m2/repository
.
To resolve artifacts from a non-standard local Maven repository, you can use the following configuration in your build.gradle
:
repositories {
maven {
url '/Users/manuelj/apache/maven/repository'
}
}
(From: [How does Gradle resolve the directory of the local maven repository?][2])
Custom Maven repositories are documented [here][3].
Storing Artifacts in the Local Maven Repository
Gradle stores resolved dependencies in its own [Dependency Cache][4]. The dependency cache is so much more than just a simple Maven artifact repository:
- Stores binaries (jars), artifact meta-data (POM, Ivy files), dependency resolution results and module descriptors.
- Tuned for performance, for example shorter file paths.
- De-duplicates artifacts: Same binaries are stored only once.
- Tracks where a dependency came from. A dependency resolved from
jcenter()
might be different to the one resolved frommavenCentral()
. - Automatic, time and usage bases, cache cleanup.
Artifacts produced by the build can be easily pushed to the local Maven repository via publishToMavenLocal
task contributed by the [Maven Publish Plugin][5].
But what about resolved dependencies? For the aforementioned reasons, Gradle cannot store dependencies in the local Maven repository. There's currently no built-in functionality to even publish dependencies to the Maven's local repository from the build script. So what are your options:
-
Create a shell script that does the necessary legwork. [Daniel Dietrich][6] once wrote one and published it on [Twitter][7] ([Gist][10]).
-
Use an artifact proxy like [Nexus][8] or [Artifactory][9]. Maven and Gradle can be configured to consume dependencies from the same proxy. This setup is quite common in professional environments and my personal preference.
[2]: https://discuss.gradle.org/t/mavenlocal-how-does-gradle-resolve-the-directory-of-the-local-maven-repository/4407 "mavenLocal() - how does Gradle resolve the directory of the local maven repository?" [3]: https://docs.gradle.org/current/userguide/repository_types.html#sub:maven_repo [4]: https://docs.gradle.org/current/userguide/dependency_cache.html [5]: https://docs.gradle.org/current/userguide/publishing_maven.html [6]: https://stackoverflow.com/users/1110815 [7]: https://twitter.com/danieldietrich/status/1146362741571145729?s=20 [8]: https://www.sonatype.com/nexus-repository-oss [9]: https://jfrog.com/artifactory/ [10]: https://gist.github.com/danieldietrich/76e480f3fb903bdeaac5b1fb007ab5ac
Solution 2 - Gradle
Use
mavenLocal()
for example:
buildscript {
ext {
springBootVersion = '2.0.0.M1'
}
repositories {
mavenCentral()
mavenLocal()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
mavenLocal()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
compile('com.oracle:ojdbc6:11.2.0.4')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
I am using Gradle 3.5
Solution 3 - Gradle
This drove me to drink.
If I do mvn install
for a project having a version of 1.1.1.SNAPSHOT
it goes into my local maven repository (~/m2/repository/...) with no errors. However, Gradle using mavenLocal()
will not attempt to locate it in the local maven repository (having used ./gradlew bootRun --debug
and inspecting the logs).
If I change the version to 1.1.1-SNAPSHOT
(note the dash), then Gradle will attempt, and will find the repository.
It doesn't make sense to me that Maven finds this to be a valid version number for local use, but Gradle completely ignores it.
Solution 4 - Gradle
I came across this issue because I'm working on a legacy project where I need to run my build with the sudo gradle build
command. The build involves copying XSD files, which require root permissions. I opted not to employ the solutions of the previous answers because I didn't want to change the build file; I didn't want to accidentally checkin my build.gradle
changes. What I found was that Gradle was checking for mavenLocal
in the /var/root/.m2
folder. My solution was to copy /Users/me/.m2/settings.xml
to /var/root/.m2
and add a line for the localRepository
to point back to my /Users/me/.m2
folder. A sample line and where to add it is:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>/Users/me/.m2/repository</localRepository>
<profiles>