Gradle / Maven: How to use in-developement dependencies? - java

Context:
I'm working on a Gradle project which depends on external libraries, also created by me. Currently I was usign a simple dependecy on project(':lib').
But this is not enough anymore, I need to release and distribute libraries as standalone components, versionned and documented. I will install Apache Archiva and publish them to an internal maven repository, so I can depend explicitly on 'com.company:lib:1.0'.
Question:
During developement, I will work on libraries and on projects at the same time. How can I test my code without publishing the libraries ? My application which used to depend on project() will now depend on a specific version. But while developing, I would like to use the local code.
Do you know what is the best process to handle this ?

One way would be to add the dependency conditionally. So for your local builds (IDE) you want to build the dependency via source. Then you can distinguish your release builds by having your releases pass a param to a build.
dependencies {
if (project.hasProperty('release')) {
compile 'com.company:lib:1.0'
} else {
compile project(':lib')
}
}
Then in your release builds to use the lib from nexus:
$ gradle -Prelease=true clean build
If you want to build the project with the lib from inside the project:
$ gradle clean build

The correct answer to this question is available in Gradle's documentation (section 23.8.3.1), and is the following:
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute module("com.company:lib") with project(":lib")
substitute module("com.company:lib2") with project(":lib2")
}
}
Personally, I used the following code, which makes all -SNAPSHOT versions to be taken from local projects instead of remote repository (if a local project is available):
configurations.all {
resolutionStrategy.dependencySubstitution {
all { dependency ->
if (! dependency.requested.version.endsWith('SNAPSHOT'))
return
if (subprojects.find { p ->p.name == dependency.requested.module })
dependency.useTarget project(":" + dependency.requested.module)
}
}
}

Related

Manage javaagent dependencies in a Java project built with Gradle

For systems that require a javaagent (say, OpenTelemetry) the docs often start with "download the agent JAR from this URL and add it to your command line". In a world where library dependencies are handled quite well using Maven Central, with stable versioning etc., the "download a JAR" approach seems primitive and insecure by comparison.
What is the best practice for acquiring javaagent libraries in a project built with Gradle? Is "download this jar" really the current state of the art?
I'm specifically interested in OpenTelemetry right now. If there's an answer (eg. a Gradle plugin) that only works for OpenTelemetry, I'm all ears.
From what I have done research, there is one gradle plugin available specifically for attaching a maven dependency as javaagent.
Quoting from plugin github repository:
This Gradle plugin tightly integrates with the Gradle application plugin to make instrumenting your application build by Gradle easy! Simply register the javaagent-application plugin and then specify the javaagent you would like to attach in the dependencies block
Example usage with otel java agent can found in the same repository here
plugins {
id("com.ryandens.javaagent.example.java-application-conventions")
id("com.ryandens.javaagent-otel-modification")
id("com.ryandens.javaagent-application")
}
dependencies {
otel("io.opentelemetry.javaagent:opentelemetry-javaagent:1.13.1")
otelExtension("io.opentelemetry.contrib:opentelemetry-samplers:1.13.0-alpha")
otelInstrumentation(project(":custom-instrumentation", "shadow"))
}
application {
// Define the main class for the application.
mainClass.set("com.ryandens.javaagent.example.App")
applicationDefaultJvmArgs = listOf("-Dotel.javaagent.debug=true", "-Dotel.metrics.exporter=none")
}
/*
see https://github.com/johnrengelman/shadow/issues/713
Currently, tasks that consume the output of the extendedAgent shadowJar task need to be made aware of
the implicit dependency (https://docs.gradle.org/7.4.2/userguide/validation_problems.html#implicit_dependency)
due to an issue with the shadowJar plugin
*/
setOf(tasks.distTar, tasks.distZip).forEach {
it.configure {
dependsOn(tasks.extendedAgent)
}
}

Gradle dependency not working on same version of build

At our company, we use Artifactory to manage artifacts and dependencies of Gradle.
We have library that was build with Gradle 6.0.1, in addition, have a micro-service that was built with Gradle 6.0.1 that is using this library as a dependency.
I verified that this library exists in the declared repo.
When we try to build the project we get an error that this library doesn't exist in the declared repositories and that we should declare the correct one.
The weird part is that if we downgrade the micro-service to Gradle version 5.6.2 the library does get download and working.
We also tested it with other older micro-services that we have based on a template project that is built with Gradle version 4.10.3 and It's also working in them.
What could be the issue?
The library I was referring to in my question didn't have the POM file published with it.
So either I will need to publish it again with the POM being generated (since the library itself was built with Gradle and not Maven - there is a way to generate POM with Gradle)
or:
I will add the following code to build.gradle file so Gradle will download the artifact even though it doesn't have POM file.
repositories {
maven {
url uri('lib')
metadataSources {
artifact()
}
}
}

How to use a parent in Gradle across different projects? [duplicate]

At my work we use Maven. I am going to try gradle for the first time. We use a common parent pom for all project which has setting for commonly used maven plugins and few comon dependencies. Is there a similar option available in gradle?
My second question is regarding release management. We use maven release plugin, which works pretty good for us. Is there something similar available in Gradle?
To share stuff within multiple projects of the same build, use allprojects { ... }, subprojects { ... }, etc. Also, extra properties (ext.foo = ...) declared in a parent project are visible in subprojects. A common idiom is to have something like ext.libs = [junit: "junit:junit:4.11", spring: "org.springframework:spring-core:3.1.0.RELEASE", ...] in the top-level build script. Subprojects can then selectively include dependencies by their short name. You should be able to find more information on this in the Gradle Forums.
To share logic across builds, you can either write a script plugin (foo.gradle), put it up on a web server, and include it in builds with apply from: "http://...", or write a binary plugin (a class implementing org.gradle.api.Plugin), publish it as a Jar to a repository, and include it in builds with apply plugin: ... and a buildscript {} section. For details, see the Gradle User Guide and the many samples in the full Gradle distribution.
A current limitation of script (but not binary) plugins is that they aren't cached. Therefore, a build will only succeed if it can connect to the web server that's serving the plugin.
As to your second question (which should have been a separate question), there are a couple of third-party release plugins available, for example https://github.com/townsfolk/gradle-release.
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.1.RELEASE'
}
}
Now, you can import dependencies without specifying a version number:
dependencies {
compile 'org.springframework:spring-core'
}
I think the best way to do things like maven parent pom is to to use gradle "apply from".
Something like this:
allprojects { // or: subprojects { ... }
apply from: "gradle/script/common.gradle"
}
The link and be a related path or an URL. Hope it helps.
Reference:
Import a Gradle script from the root into subprojects
Super POM, Parent POM type of hierarchy management in Gradle
I too wanted this type of feature, I have created a plugin to provide this here: https://github.com/boxheed/gradle-pater-build-plugin
You can convert the Parent pom content in to Gradle init file very easily.
Gradle init script provides same functionality as Maven super/parent pom. The basic difference is that you can call init script
Run time
As many as of them This gives us flexibility to change the init
script on run time but doubt of not tracking the changes.
You need to take repository, distribution management, profiling and other checks like findbugs, checkstyle etc in to init script.
The detail is huge, You can find complete information here by me.
http://www.scmtechblog.net/2015/12/how-to-migrate-parent-pom-from-maven-to.html
I have explained about gradle release plugin which is similar to maven release plugin.
to achive your goal you could apply the concept of 'multiproject build' explained in the gradel user guide here
Basically you can create an umbrella project which define a set of common configurations by creating a gradle.build file and a gradle.settings file.
The build file contains the properties, dependencies and plugins commons to all projects, the settings.gradle defines what subprojects inherits those configurations.
Moreover, to have an idea of the gradle plugin ecosystem you could check this source.
It is currently not possible, if you want the parent to be cached locally and stored in a Maven repository.
I have added feature request here:
http://forums.gradle.org/gradle/topics/support_for_gradle_parent_shared_between_projects_cached_locally

How to convert Gradle to maven in eclipse

I want to migrate from gradle to maven I tried and build successfully but I am facing issue while running my application
I took this gradle project https://github.com/spring-projects/spring-security-kerberos from git, its working fine as gradle project.
But my requirement is maven project please tell me how I can do it.
You can try and add the Maven Publishing plugin and its maven-publish in order to generate a pom.xml.
A MavenPublication is the representation/configuration of how Gradle should publish something in Maven format.
You directly add a named Maven Publication the project's publishing.publications container by providing MavenPublication as the type.
publishing {
publications {
myPublicationName(MavenPublication) {
// Configure the publication here
}
}
}
using archiveTask you can generate the pom.xml
http://www.gradle.org/docs/current/userguide/maven_plugin.html#sec:maven_pom_generation

Using Gradle to include my own Java library in a project

Disclaimer: I'm very new to Gradle and Dependency Management. I tried reading the documentation but just couldn't get through the sheer amount of information. I also couldn't find anything useful to answer my question, so sorry if this has been answered before, I tried searching...
So my situation is as follows: I have one Java project that's supposed to give me a standardized way of using program configurations using JSON files. This project has a dependency on Gson. So far so good, I simply added compile 'com.google.code.gson:gson:2.6.2' to that projects dependencies and all's fine, the library shows up as External Library in Idea, and I can use it and stuff.
Now I want to use that project in other projects to make use of the configuration stuff. And I can not for the life of me figure out how to add the project or the library jar to other projects using Gradle.
I tried things like copying the library jar to the libs folder of the projects to use it in and adding compile files('./libs/myLibrary-0.0.1.jar') to the dependencies list, or adding the jar as a library via the Project Structure thing in Idea. None of these methods worked, and I'm at my wits end.
Any help would be appreciated.
If you or your company have a central binary repository, such as artifactory. Then you should set up publishing your jar there.
But since you haven't mentioned a central repository, I'll assume that you don't have one, and are simply trying to get your dependency to work on a single machine. In that case, what I suggest doing is this:
Add the maven-publish plugin to your dependency project:
apply plugin: 'maven-publish'
Also make sure that you define the group, version and name variables of your project (see here). You'll need them later. Then add a publishing definition that will tell maven-publish to publish all classes:
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
Using these settings you should now be able to run the publishToMavenLocal task. Do it. If successful, the dependency jar should now be in your local maven repository (~/.m2/repository)
Now, add mavenLocal as a repository in the project that needs the dependency:
repositories {
mavenLocal()
}
(you might want to add additional repositories here, such as mavenCentral())
Also add your jar's group, name, and version just like your gson dependency:
compile 'yourgrou:yourname:yourversion.
Gradle should now be able to fetch the dependency from the local maven repo.
You have couple of options. First and easy is to build your base project and available in your local maven repository and use it. To make your project available is your local maven repo, use maven plugin. In your build.gradle file, add the following.
apply plugin: 'maven'
Now use gradle clean build install to publish the jar to your local repo. Remember that install task is the one actually put your jar into your local.Then head over to your other project which depends on this one and tell it to look into your local maven repo by adding mavenLocal to the repositories.
repositories {
mavenCentral()
mavenLocal()
}
Another option is, if you are using centralized repo in your company, you can publish your base jar and use it in the other project. Check out the documentation.

Categories