I have the following project strucuture:
example
├── build.gradle
├── module1
│ ├── build.gradle
│ └── main
│ ├── java
│ │ ├── module-info.java
│ │ └── com.example.module1
│ │ └── Example.java
│ └── resources
│ └── application.yml
└── module2
├── build.gradle
├── main
│ ├── java
│ │ ├── module-info.java
│ │ └── com.example.module2
│ │ └── Example2.java
└── test
module1 build.gradle
repositories {
maven {
url 'http://download.osgeo.org/webdav/geotools/'
name 'Open Source Geospatial Foundation Repository'
}
maven {
url 'https://repo.boundlessgeo.com/main/'
name 'Boundless Maven Repository'
}
maven {
url 'http://repo.boundlessgeo.com/snapshot'
name 'Geotools SNAPSHOT repository'
mavenContent {
snapshotsOnly()
}
}
mavenCentral()
jcenter()
}
dependencies {
implementation "org.geotools:gt-main:$geotoolsVersion"
}
module2 build.gradle (depends on module1)
repositories {
mavenCentral()
jcenter()
}
dependencies {
implementation project(':module1')
}
The problem is that when resolving the dependencies for module2, it is unable to find the transitive dependencies of module1, and so I get the following error:
FAILURE: Build failed with an exception.
* What went wrong:
A problem occurred configuring project ':module2'.
> Could not resolve all files for configuration ':module2:runtimeClasspath'.
> Could not find org.geotools:gt-main:21.2.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/org/geotools/gt-main/21.2/gt-main-21.2.pom
- https://repo.maven.apache.org/maven2/org/geotools/gt-main/21.2/gt-main-21.2.jar
- https://jcenter.bintray.com/org/geotools/gt-main/21.2/gt-main-21.2.pom
- https://jcenter.bintray.com/org/geotools/gt-main/21.2/gt-main-21.2.jar
Required by:
project :module2 > project :module1
It looks like it is only searching for the transitive deps of module1 using the repositories declared in module2 instead of in module1.
Interestingly, if I change the dependency in module2 to:
dependencies {
compileClasspath project(':module1')
}
The dependencies are resolved. However this means that at runtime, module1 is not part of the classpath, so running the application still fails.
How can I fix this?
The problem is that project dependencies do not leak their repository locations when depended on.
The fix is to move the repositories into the root build.gradle. Something like:
subprojects {
repositories {
//https://docs.geotools.org/latest/userguide/build/maven/repositories.html
maven {
url 'http://download.osgeo.org/webdav/geotools/'
name 'Open Source Geospatial Foundation Repository'
}
maven {
url 'https://repo.boundlessgeo.com/main/'
name 'Boundless Maven Repository'
}
}
}
See the following github issues:
https://github.com/gradle/gradle/issues/4106
https://github.com/gradle/gradle/issues/8811
Related
This is definitely a beginner gradle question, but I just can't make it work.
I have a library and an application which depends on the library.
.
/ library
/ application
I can install the library through gradle install in ./library, then have the application depend on the library through the group/name/version, and pick up the library through the mavenLocal() repository in the application build.gradle, then build the app in the application folder. And that works.
But I'd like to have a project, and that I could have a single command to build the application and, if needed, the library too (similar to the maven -am flag).
Here's what I have right now, in the parent folder, build.gradle:
subprojects {
apply plugin: "java"
repositories {
mavenCentral()
}
}
project(':application') {
dependencies {
compile project(':library')
}
}
and in the same folder I have settings.gradle:
include ':library', ':application'
Again, if I go in the library folder and run gradle install, it works. I get the artifact in my ~/.m2.
But now with the configuration I described, if I go in the root folder and run gradle shadowJar.. and the shadowJar task is present only in application, then gradle tries to compile the library but fails, apparently because it doesn't pick up the library dependencies.
* What went wrong:
Execution failed for task ':library:compileJava'.
> Compilation failed; see the compiler error output for details.
the errors are like, for instance:
Task :library:compileJava FAILED
.../DateTimeAdapter.java:5: error: package javax.xml.bind.annotation.adapters does not exist
import javax.xml.bind.annotation.adapters.XmlAdapter;
and sure enough these are dependencies in the library/build.gradle =>
implementation 'com.fasterxml.jackson.core:jackson-core:2.8.8'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.8.8'
So my question is how do I specify the application dependency on library, so that I can run a single command and have maven build the library if needed, then the application.. I thought what I did would have gotten the first part through, but it fails, apparently due to library's transitive dependencies. I actually expect I need to handle a second part after that, which is how to specify the dependency in the application build.json. I may have to switch from specifying the maven group/name/version coordinates to the project name, but I didn't get that far yet.
I would definitely not want to list the library dependencies in the root gradle file: I'd like library to handle its dependencies, and application its dependencies, I'd like to keep the root gradle file small.
application is unable to see the dependencies of library because you have declared the Jackson dependencies as an implementation detail of library.
What you intended to do was expose your library and it's dependencies as an api for consumers.
Dependencies declared in the implementation configuration can be thought of as "private" meaning consumers of your library should not access methods/classes that use those dependencies otherwise they will face errors like the one you are. api is basically the opposite of implementation.
The api configuration is available via the java-library plugin.
Full working example for what you're trying to achieve (Kotlin DSL):
├── application
│ └── build.gradle.kts
├── build.gradle.kts
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
│ └── build.gradle.kts
└── settings.gradle.kts
Root project build.gradle.kts:
subprojects {
apply {
plugin("java-library")
}
repositories {
jcenter()
}
}
settings.gradle.kts:
rootProject.name = "example-proj"
include("application")
include("library")
Library build.gradle.kts:
dependencies {
api("com.fasterxml.jackson.core:jackson-core:2.10.0")
api("com.fasterxml.jackson.core:jackson-databind:2.10.0")
}
Application build.gradle.kts:
dependencies {
implementation(project(":library"))
}
I have a gradle multi project.
'root' has 2 sub projects which named 'domain' and 'web'. 'web' needs to use classes which are declared in 'domain' project.
However whenever I add compile project(':domain') into dependencies of 'web'.
Intellij says 'root_main', 'root_test', 'web_main', 'web_test' are not imported from Gradle anymore, which I don't want to.
Could you tell me how I can add dependency 'domain' into 'web'?
The structure is below :
root
├── build.gradle
├── domain
│ ├── build.gradle
│ └── src
│ └── main
│ └── test
│
├── web
│ ├── build.gradle
│ └── src
│ └── main
│ └── test
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
'build.gradle' in root
version '1.0-SNAPSHOT'
allprojects {
group = 'com.sample.projects.multi'
apply plugin: 'java'
apply plugin: 'eclipse'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
}
'build.gradle' in domain
version '1.0-SNAPSHOT'
dependencies {
}
'build.gradle' in web
version '1.0-SNAPSHOT'
dependencies {
compile project(':domain')
}
For ppl who might have same issue with me, I resolved this by updating Intellij to newer one. Mine was 2017.1 and I updated it to 2018.1.
I am pretty new to gradle.
This is my project configuration
Project
.
├── build.gradle
├── sub-project-1
│ ├── build.gradle
├── tests
│ ├── rest
│ └── unit
│ ├── build.gradle // Lets call this unit_build.gradle
My unit tests have a dependency on derby.jar, and the unit_build.gradle has the following:
dependencies{
..
testCompile fileTree(dir: "${System.getProperty('java.home')}/../db/lib", include: "derby.jar")
testCompile fileTree(dir: "${System.getProperty('java.home')}/../db/lib", include: "derbyclient.jar")
}
Note: We have our own repository and derby is not included in that. So we use it by adding it from local.
This works fine when I run a gradle build, followed by my test task.
But we also publish the jar to a test server and run it there where it fails with a class not found exception on derby.
What can be the reason? What should be done to fix this?
Gradle version - 1.12
this happens because you choose wrong target dependency configuration. I mean testCompile, instead of this you should use: testRuntime or testRuntimeClasspath
So I'm trying to create a root level ear project that will include multiple war projects and I can't seem to get it to work. To pare it down to the simplest level, lets suppose I have a directory structure like this:
myEar/
├── build.gradle
├── myWar1
│ ├── build.gradle
│ └── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── foo
│ │ └── hello.java
│ ├── resources
│ └── webapp
│ ├── test.html
│ └── WEB-INF
│ └── web.xml
├── myWar2
│ ├── build.gradle
│ └── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── foo
│ │ └── hello.java
│ ├── resources
│ └── webapp
│ ├── test.html
│ └── WEB-INF
│ └── web.xml
├── settings.gradle
└── src
└── main
└── application
└── application.xml
Each build.gradle file in the myWarX subporjects is simply this:
defaultTasks 'war'
apply plugin: 'war'
When I run gradle from inside the myWar1/2 folder I get the expected output:
jar -xvf myWar1.war
created: META-INF/
inflated: META-INF/MANIFEST.MF
created: WEB-INF/
created: WEB-INF/classes/
created: WEB-INF/classes/com/
created: WEB-INF/classes/com/foo/
inflated: WEB-INF/classes/com/foo/hello.class
inflated: WEB-INF/web.xml
inflated: test.html
Now at the root project level myEar, I have the following settings.gradle file:
include ":myWar1", ":myWar2"
and build.gradle looks like this:
defaultTasks 'assemble'
allprojects {
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'
apply plugin: 'ear'
}
dependencies {
deploy project(path: ':myWar1', configuration: 'archives')
deploy project(path: ':myWar2', configuration: 'archives')
}
Now when I run this, it builds an myEar.ear file sure enough but both the war projects are being listed as myWar1/2.ear in the archive. In addition, if I expand out those ear files, it is missing things like the html files and the web.xml:
jar -xvf myEar.ear
created: META-INF/
inflated: META-INF/MANIFEST.MF
inflated: myWar1.ear
inflated: myWar2.ear
inflated: application.xml
inflated: META-INF/application.xml
jar -xvf myWar1.ear
created: META-INF/
inflated: META-INF/MANIFEST.MF
created: com/
created: com/foo/
inflated: com/foo/hello.class
inflated: META-INF/application.xml
It seems like there should be a simple solution to this but I can't for the life of me find it. Any help would be gratly appreciated.
Thanks,
Marcus.
ok I'm an idiot. It was because I am applying the 'ear' plugin to allprojects. If I replace:
allprojects {
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'
apply plugin: 'ear'
}
with simply
apply plugin 'ear'
everything works as intended.
My project layout is like this
A
├── B
│ ├── build.gradle
│ └── Example-0.0.1.jar
├── build.gradle
├── C
│ ├── build.gradle
│ └── src
│ └── main
│ └── java
│ └── com
│ └── sample
│ └── Hello.java
└── settings.gradle
Now, B uses maven-publish to publish Example-0.0.1.jar to local maven archives (i.e ~/.m2/repositories)
C is a java project. The Hello.java file uses the Example jar file.
I am using gradle 2.2 to build this project.
I have
$ cat A/build.gradle
allprojects {
repositories {
mavenCentral()
mavenLocal()
}
}
and
$ cat A/settings.gradle
include ':B'
include ':C'
and
$ cat A/B/build.gradle
apply plugin: 'maven-publish'
publishing {
publications {
maven(MavenPublication) {
groupId 'com.example'
artifactId 'abc'
version '0.0.1'
artifact 'Example-0.0.1.jar'
}
}
}
and
$ cat A/C/build.gradle
apply plugin: 'java'
apply plugin: 'maven'
dependencies {
compile project(':B')
compile 'com.example:abc:0.0.1'
}
Now, whenever I run any gradle command, I get the following error:
$ gradle tasks
Execution failed for task ':tasks'.
> Could not determine the dependencies of task ':C:compileJava'.
Is there any way such that task B:publishToMavenLocal be run before building of C in order to include the jar?
I was also stuck with the same issue.
Figured out a way to achieve this. I added following to parent build.gradle file and everything is now working as expected.
project(':project-B').tasks.compileJava.dependsOn project(':project-A').tasks.install
So now when i am executing the build, artifacts of project-A is being installed to local repository and then project-B is able to take them from there. Good Luck!!