I am working on a task where parent project with all the required dependencies are mentioned in gradle and this project to be used as parent, basically a BOM which has all the components mentioned and can be usedrefered as dependency in other project
Say for example, Spring boot parent and other dependencies are mentioned in gradle file, which I can refer this project in other projects.
The projects are not in multi module structure.
Maven equivalent:
<dependencyManagement>
<dependencies>
<dependency>
</dependency>
</dependencies>
</dependencyManagement>
similar tags - pluginManagement, build, profiles etc
If you can refer me to the resources or some head start would be helpful.
Thanks.
Sharing common dependency version across projects can be accomplished using a platform:
A platform is a special software component which can be used to control transitive dependency versions. In most cases it’s exclusively composed of dependency constraints which will either suggest dependency versions or enforce some versions. As such, this is a perfect tool whenever you need to share dependency versions between projects.
With the Java Platform plugin, you can create a project to accomplish this (Gradle does not have a 1:1 equivalent of parent):
// build.gradle
// Let's call this project com.example:my-parent-bom
plugins {
id 'java-platform'
}
javaPlatform {
allowDependencies()
}
dependencies {
// Import other BOMs
api platform('org.springframework.boot:spring-boot-dependencies:2.4.4')
api platform('org.springframework.cloud:spring-cloud-dependencies:2020.0.2')
// Define version for dependencies not managed by the above BOMs
constraints {
api 'commons-httpclient:commons-httpclient:3.1'
runtime 'org.postgresql:postgresql:42.2.5'
}
}
Then you can publish this platform like any other Gradle project and consume it:
// some other build.gradle
plugins {
id 'java'
}
dependencies {
implementation platform('com.example:my-parent-bom')
}
Related
I work on a project with multiple grails services, plugins and libraries, all built with gradle with their dependencies declared in build.gradle files, one per project, this makes sense, I hope.
In maven I used to be able to declare versions of all dependencies in one parent project pom, or a pom template, and only include the dependencies in the projects that required them without the versions. This made upgrading dependencies easy in one place. Is there a simple way to do this in gradle?
Pseudocode example:
master_template/build.gradle
dependencies {
joda-time:joda-time:2.9.1
cglib:cglib:3.2.9
javax.servlet:javax.servlet-api:3.1.0
}
service_a/build.gradle
parent: master_template
dependencies {
joda-time:joda-time
javax.servlet:javax.servlet-api
}
service_b/build.gradle
parent: master_template
dependencies {
cglib:cglib
javax.servlet:javax.servlet-api
}
You can create a multi module project like you would do in maven with a parent pom.
In order to manage the dependency in the parent, I use the spring dependency management plugin.
You parent build.gradle would look like:
subprojects {
apply plugin: "io.spring.dependency-management"
sourceCompatibility = 1.8
targetCompatibility = 1.8
check.dependsOn dependencyCheckAggregate
repositories {
mavenLocal()
jcenter()
// other repos
}
dependencyManagement {
def jacksonVersion = "2.+"
dependencies {
dependency "com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion"
dependency "com.fasterxml.jackson.core:jackson-core:$jacksonVersion"
dependency "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion"
dependency "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:$jacksonVersion"
dependency "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion"
}
}
}
Now, you can add dependencies to your submodules without specifying version.
You can easily achieve what you want by using Gradle's default apply from: 'other.gradle', so no additional plugins are needed.
In my micro-service project I'm using something like that:
common-gradle/env.gradle
apply plugin:'groovy'
ext.compile = [ 'joda-time:joda-time:2.9.1', 'cglib:cglib:3.2.9` ]
ext.testCompile = [ 'org.spockframework:spock-core:1.3-groovy-2.5' ]
common-gradle/dependencies.gradle
dependencies {
compile ext.compile
testCompile ext.testCompile
}
And the usage
service_a/build.gradle
apply from:'../common-gradle/env.gradle'
ext.compile << 'ch.qos.logback:logback-classic:1.2.3'
apply from:'../common-gradle/dependencies.gradle'
Thus each of my build.gradle files contain only 3-5 lines of critical information like project name and version.
You don't need to import the common-gradle as a project in your IDE, you can simply use symlinks to avoid using external references. Also during build on a Jenkins-like pipeline, the only thing you have to do is to check out the common-gradle repo into your working dir.
I am trying to follow this Spring Boot/Vaadin guide however I'm using Gradle, not Maven.
At the very top of that guide they say to use the following Maven XML:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId>
<version>10.0.11</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
However I don't see a dependencyManagement task available via Gradle. So I ask: how do I replicate the same behavior as the <dependencyManagement/> XML element above over in "Gradle land"?
Update: current attempt
dependencyManagement {
imports {
mavenBom 'com.vaadin:vaadin-bom:10.0.11'
}
}
Only problem with this is that when I add it to my build.gradle and then run ./gradlew clean I get the following Gradle error:
"Could not find method dependencyManagement() for arguments..."
This should give you a working build:
plugins {
// the Gradle plugin which provides the “dependencyManagement” block
id 'io.spring.dependency-management' version '1.0.6.RELEASE'
// add Java build functionality to be able to follow the Vaadin guide
id 'java'
}
dependencyManagement {
imports {
// the Maven BOM which contains a coherent set of module versions
// for Vaadin dependencies
mavenBom 'com.vaadin:vaadin-bom:10.0.11'
}
}
repositories {
// find dependency modules on Maven Central
mavenCentral()
}
dependencies {
// the dependency module you need according to the Vaadin with
// Spring Boot guide; the version of the module is taken from the
// imported BOM; transitive dependencies are automatically taken
// care of by Gradle (just as with Maven)
compile 'com.vaadin:vaadin-spring-boot-starter'
}
Run ./gradlew dependencies --configuration compileClasspath to see that all dependencies are available on your Java compile classpath now.
Edited to reply to the question in the comments: indeed, the import of the BOM leads to a slightly different set of dependencies than would be used without it. You can see the dependencies difference like so:
./gradlew dependencies --configuration compileClasspath > with-BOM.txt
Remove the dependencyManagement block and add a version to the single dependency: compile 'com.vaadin:vaadin-spring-boot-starter:10.0.11'
./gradlew dependencies --configuration compileClasspath > without-BOM.txt
diff -u with-BOM.txt without-BOM.txt
You can see slight differences like org.webjars.bowergithub.webcomponents:webcomponentsjs:1.2.6 being used with the BOM and version 1.2.2 without it. The reason for that can be found in the BOM where version 1.2.6 is defined and where the authors also mention the reason for that: “Transitive webjar dependencies, defined here for repeatable builds”
Generally maven dependencyManagement tag is used to import bom or control transitive versions.
Gradle does that with platform component, like below example.
dependencies {
implementation platform('com.vaadin:vaadin-bom:10.0.11')
implementation ('com.vaadin:vaadin-core')
}
This does not force you to depend on spring plugin for importing bom.
I have a commons gradle project which is a shared library for all my other projects.
In the build.gradle of dependent project, I included the commons jar as following:
dependencies {
...
runtime files('../commons/build/libs/commons-1.0.jar')
}
And this builds fine with the relative path. But this feels like hard-coding a specific library. What is the standard way to achieve the builds in this case?
You can publish the common jar to Your local maven repository. But If You are developing with in a team, You should publish to a repository manager where other parties have also access to.
And in the dependent projects You simply add this common jar, like You are adding a third party library. With this way You don't have to store dependent jar files on Your version control system. When projects are developed by different parties, this way would be more convenient.
Example of using mavenlocal
// Common project build.gradle
apply plugin: 'maven-publish'
version = '2.0'
...
publishing {
publications {
maven(MavenPublication) {
groupId = 'com.gradle.sample'
artifactId = 'project1-sample'
from components.java
}
}
}
You can use gradle publishToMavenLocal to publish common project to mavenlocal. (Dependent projects can not use the new versions of common jar, unless You publish it to mavenlocal in this case)
// Dependent project build.gradle
repositories {
mavenLocal()
}
dependencies {
implementation 'com.gradle.sample:project1-sample:2.0'
....
}
Check the following link for details.
https://docs.gradle.org/current/userguide/publishing_maven.html
I'm on a team where maven and gradle is used, and I have a gradle project that wants to generate a functioning pom file so that our maven users can keep using maven.
I have solved this problem so far as generating a pom with appropriate dependencies as follows:
build.gradle excerpt:
task createpom(dependsOn: 'build') << {
pom {
project {
groupId project.group
artifactId project.name
version project.version
}
}.writeTo("pom.xml")
}
build.finalizedBy(createpom)
This works well for creating just the dependencies on a pom, but gradle's maven plugin API does not seem to support defining the contents of the <build> tag, which I need to import certain plugins for a successful maven build.
In short, I need one of the following:
Postprocessing the build tag into the generated POM. I could do it by manipulating the file directly, but prefer not to.
Splitting the POM into two parts, one with only gradle managed dependencies, and one with only the human managed things. Unfortunately, I don't see any means of arbitrarily naming a pom dependency by file name; only solutions that involve adding a pom only project or using multi-module builds, neither of which I like considering that I have no need for a shareable parent pom or multi-module project. I would much prefer something akin to <import>my/arbitrary/path/buildstuff.xml</import>, since all a really need to do is glue two halves of a POM for the same project/lifecycle together.
Is there a better way of accomplishing this other than what I've found so far?
I went with the XML tweaking solution, which proved to be far more elegant than I anticipated. Implementation involved adding an unmanaged pom to my project directory to hold the human-managed parts of the build, and modifying my createpom task as such:
task createpom(dependsOn: 'build') << {
pom {
project {
groupId project.group
artifactId project.name
version project.version
}
}.withXml {
def templateXml = (new XmlParser()).parse('pom-unmanaged.xml')
asNode().append(templateXml.build)
}.writeTo("pom.xml")
}
pom-unmanaged.xml takes the form of a typical pom, minus the bits that my gradle build script generates.
In maven, you can declare depenencies versions in dependency management section.
Say I have such pom for managing default versions of some libraries for all of my projects (so I don't have to repeat them all over again and so I can ensure some consistency across all of my projects).
Then I have multiple projects(project A and project B) which have this pom set as parent pom. If in project A I want to use spring.jar, and I have spring.jar defined in dependency-management of A's parent pom, I don't have to define spring version in A's pom again, I just define that it depends on spring. So far it's ok, is pretty simple how to do it in gradle too (http://stackoverflow.com/questions/9547170)
What I'm wondering about is this situation:
Imagine that spring 3.0 depends on hibernate 3.0. In A's parent pom I have defined hibernate dependency in dependency-management section with version 3.1, but spring is not defined there. Spring is defined in A's pom (with version 3.0). Dependency resolution in maven for project A would result in fetching spring 3.0 and hibernate 3.1 - because despite fact that spring 3.0 depends on hibernate 3.0, dependency-management of A's parent pom overrides hibernate version, so 3.1 would be used instead.
Is there way of defining something similar in gradle? Note that I didn't have to specify hibernate in A's pom specificly and also it is not specified as dependency in A's parent pom - it is only in dependency-management section of A's parent pom.
The io.spring.dependency-management plugin allows you to use a Maven bom to control your build's dependencies:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "io.spring.gradle:dependency-management-plugin:0.5.3.RELEASE"
}
}
apply plugin: "io.spring.dependency-management"
Next, you can use it to import a Maven bom:
dependencyManagement {
imports {
mavenBom 'io.spring.platform:platform-bom:1.1.4.RELEASE'
}
}
Now, you can import dependencies without specifying a version number:
dependencies {
compile 'org.springframework:spring-orm'
compile 'org.hibernate:hibernate-core'
}