Gradle: use the bom of a dependency - gradle

Using gradle, in a projectA we import the resteasy BOM:
compile platform('com.fasterxml.jackson:jackson-bom:2.13.2')
compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
Then in a projectB we import projectA
implementation("com.my.service:projectA:0.0.1-SNAPSHOT")
Now, when we compile projectB, jackson-datatype-jsr310 cannot be found. It cannot determine the version to use. Same if in projectB I want to import another jackson dependencies, that are defined in the BOM.
How can I automatically use the same version in projectB?

The compile scope is not inherited transitively by projects that use your module as a dependency.
To set a transitive dependency (being a BOM or of any other kind) you should use the api scope.
However, note that for using the api scope, you need to tell Gradle that your project is a library (and not an executable module). To do this, you should add the java-library plugin.
Your project A should be defined this way:
plugins {
id 'java-library'
}
dependencies {
api platform('com.fasterxml.jackson:jackson-bom:2.13.2')
api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
}
You can check all the details at the java-library plugin documentation.

Related

Gradle BOM project

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')
}

Which dependencies are added to a Gradle project which uses a 'project lib dependency' and is this configurable?

Gradle project lib dependencies are a means of defining a project as requiring, as one of its dependencies, the output from another project.
The documentation states:
A “lib” dependency is a special form of an execution dependency. It
causes the other project to be built first and adds the jar with the
classes of the other project to the classpath. It also adds the
dependencies of the other project to the classpath.
However, which dependencies of the project are added? Is it the compile, implementation or runtime dependencies, for instance? Is this configurable? i.e. how would I configure a project to require the output of another project and the dependencies from an arbitrary configuration of that other project?
For instance, in my root project, I can define project1 to depend on project2:
project(":project1") {
dependencies {
implementation project(':project2')
}
}
How do I add the dependencies of an arbitrary configuration of :project2 (let's say it's called myConfiguration) to project1?
The answer is contained within the DSL documentation for Dependencyhandler.
By default, when you declare dependency to projectA, you actually
declare dependency to the 'default' configuration of the projectA. If
you need to depend on a specific configuration of projectA, use map
notation for projects:
configurationName project(path: ':projectA', configuration: 'someOtherConfiguration')

How to build a jar from a multi-module project when using Gradle?

I'm working on a multi-module library project which I build with Gradle. I have a dependency to another module of this project in my dependencies section:
dependencies {
compile project(':my-other-module')
}
My problem is that I want to build a .jar file which only contains the local modules in the final file, not its transitive dependencies. I tried this:
jar {
from project(':my-other-module').configurations.compile.collect { zipTree it }
}
but this added all the transitive dependencies as well. I want to create a .jar which only contains my own files, so the users of this library can have their own versions of transitive dependencies. How can I do so?
Further clarification:
I have dependencies declared in my project to external jars like apache-commons. I want these not to be in my resulting .jar file but I want the users of my library to be able to just add my library as a dependency and let Maven/Gradle download the transitive dependencies. I don't want these transitive dependencies to be in the .jar file I deploy to Maven Central. compileOnly is not an option since the dependencies I use like apache-commons are not provided by a framework or a container. They need to be present as compile dependencies. I just want to build and deploy a .jar file which has all the files in my project which has multiple modules.
I am not sure it'll help you or not but, you can try this.
In your build.gradle file, customize your jar task as follows:
// This closure will return the full directory path of folder where your classes are built
ext.moduleClassPath = { moduleName ->
def classOutputDirConst = "/classes/java/main"
return "${project(":${moduleName}").buildDir}${classOutputDirConst}"
}
// Now jar task will include only the built file of specified project
jar {
from(moduleClassPath("projectName1"), moduleClassPath("projectName2"))
}
Check the reference for the from(SourcePaths) method here: Reference: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:from(java.lang.Object[])
Gradle has a compile-only dependency concept, similar to Maven's provided scope:
Compile-only dependencies are distinctly different than regular compile dependencies. They are not included on the runtime classpath and they are non-transitive, meaning they are not included in dependent projects.
The dependencies you don't want can be declared in the compileOnly configuration, rather than compile, eg:
dependencies {
compileOnly 'javax.servlet:servlet-api:2.5'
}
compileOnly is not even visible to unit tests, by default. We change this in a common gradle snippet which we include in each build:
// compileOnly isn't visible to tests by default, add it
plugins.withType(JavaPlugin).whenPluginAdded {
sourceSets {
test.compileClasspath += configurations.compileOnly
test.runtimeClasspath += configurations.compileOnly
}
}
For the second part, for which I believe you want to create a single "fat" jar,
I would suggest creating your jar using the very good Shadow Plugin, rather than manually extending the jar task. By default, the shadow plugin will not include anything in the compileOnly configuration in the resulting jar.

gradle earlib not pulling transitive libraries

I got gradle 3.5.1 and using ear plugin. The documentation says that deploy configuration is not transitive but earlib actually is (https://docs.gradle.org/3.3/userguide/ear_plugin.html). My configuration is a below
dependencies {
earlib(
"org.mybatis:mybatis:3.2.8"
)
}
It was supposed to get a few other transitive libraries but here is all I get when I run gradle dependencies
earlib - Classpath for module dependencies.
\--- org.mybatis:mybatis:3.2.8
What am I doing wrong here?
Actually, you are doing nothing wrong. Your module dependency org.mybatis:mybatis:3.2.8 simply does not define any (mandatory) transitive dependency, since every compile or provided dependency is marked as optional.
According to the Maven docs,
If a user wants to use functionality related to an optional dependency, they will have to redeclare that optional dependency in their own project.

call java function in gradle script

I have a java class which does some kind of functionality, one of these function returns something that I need to use it into gradle script to set the project properties.
I had achieved it by creating an artifact of project and used that artifact by adding it into classpath, that gave me accessibility of that class and function.
buildscript {
repositories {
jcenter()
maven{
url 'http:localhost:8081/artifactory/temp'
}
}
dependencies {
classpath "utility:sampleutility:1.0"
}
}
import com.polsys.utility.MyUtil
dependencies {
compile 'org.slf4j:slf4j-api:1.7.13'
compile 'HRP:'+new MyUtil().callMe()+':1.0'
//callme function returns the name of artifact.
testCompile 'junit:junit:4.12'
}
Now, I had achieved it by the way as mentioned above that is by creating artifact, add that artifact into classpath, then import classes and use function. Is this any way by which I can call functions of current project? so I can merge that functionality which is available in the artifact into current project.
Simple way is to put your Java/Groovy code under buildSrc dir. Gradle will compile it and you'll be able to call this code from your buildscript. Check https://docs.gradle.org/current/userguide/custom_plugins.html and related docs.
To make your java code available to gradle script you need to have your java code under the directory hierarchy given below:
ProjectRootDirectory
buildSrc
src
main
groovy/java
YourPackages(in my case java packages and classes)
This is the path where gradle script looking for external plugins. Now you can import and access classes into gradle script(you will not end up with "unable to resolve class" error).

Resources