How to use pom type dependency in Gradle - gradle

I need to produce transitive dependency from my Java library which is of type pom. Here is an example on how I'm doing it:
plugins {
`java-library`
`maven-publish`
}
repositories {
// some maven repo
}
dependencies {
// This is POM type dependency:
api("org.apache.sshd:apache-sshd:1.6.0") {
exclude(group = "org.slf4j")
}
}
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
The problem with this configuration is that in the published pom.xml of my library the dependency is of type jar (by default) and declared like that:
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>apache-sshd</artifactId>
<version>1.6.0</version>
<!-- Should declare pom type -->
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>*</artifactId>
<groupId>org.slf4j<groupId>
</exclusion>
</exclusions>
</dependency>
So when I try to use my published library from another project it fails as there is no such artifact as apache-sshd because it's type should be pom. So how to correctly publish desired dependency using Gradle?
Running on Gradle 5.3.1 with Kotlin DSL.

Try to use following construction for declaring dependency in Gradle
api("org.apache.sshd:apache-sshd:1.6.0#pom") {
exclude(group = "org.slf4j")
isTransitive = true
}
Looks like Gradle consumes all dependencies as jar type by default. And Maven plugin generates dependency section in pom file by using this extracted type. For pom dependency it is necessary to put correct value into type field of generated file. But if you put pom extension for your dependency, Gradle won't resolve transitive dependencies that are declared in this artifact. Set the value of transitive flag resolves this issue.

I have used it in the following way:
compile(group: "dependency_group", name: "dependency_name", version: "dependency_name", extension: "pom")
and if you want to exclude the transitive dependencies
add transitive flag and set it to false
compile(group: "dependency_group", name: "dependency_name", version: "dependency_name", extension: "pom"){
transitive = false
}

Related

Gradle maven-publish dependency scope

I have a pretty simple Gradle Kotlin project.
plugins {
id 'application'
id 'maven-publish'
}
repositories { mavenCentral() }
dependencies {
compile 'com.google.guava:guava:31.1-jre' // 'compile' is deprecated
}
publishing {
publications {
maven(MavenPublication) {
groupId = 'de.mabe'; artifactId = 'project1'; version = '1.0'
from components.java
}
}
}
When I start gradle publishToMavenLocal it generates a correct pom file with a correct dependency:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
<scope>compile</scope> <!-- this scope is important -->
</dependency>
Now I replaced the compile with implementation in the gradle script.
implementation 'com.google.guava:guava:31.1-jre'
Unexpectedly this changes the scope in the pom file from compile to runtime.
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
<scope>runtime</scope> <!-- compile EXPECTED ?!?! -->
</dependency>
What do I have to do to get the previous pom back?
That is by design. The semantics of the implementation configuration is to declare dependencies that are internal to a module. By mapping it to the runtime scope of a Maven pom, it ensures that it doesn't leak onto the compilation classpath of consumers. This has a few advantages like being more free to swap out transitive depencies with less risk of affecting consuming modules, to make compilation faster and more.
If you need to make a transitive dependency part of the compile scope, i.e. expose it on the compilation classpath of consuming projects, you need to use the api configuration instead. This is available by applying the java-library plugin.
For example (Groovy DSL):
plugins {
id 'java-library'
id 'maven-publish'
}
dependencies {
implementation 'org.apache.commons:commons-math3:3.6.1' // <- Maps to the Maven runtime scope
api 'com.google.guava:guava:30.1.1-jre' // <- Maps to the Maven compile scope
}
publishing {
publications {
maven(MavenPublication) {
groupId = 'de.mabe'; artifactId = 'project1'; version = '1.0'
from components.java
}
}
}
You can read more about the separation between API and implementation in the Gradle user guide here.

How to use gradle feature variant dependecies in tests?

I am migrating a Maven library project to Gradle. The original project also has optional dependencies. I use the java-library plugin but moving the formerly optional dependencies to implementation results in runtime dependencies instead of compile. So I tried the gradle feature variants which results in the right dependencies in the pom.xml. But doing so results is failing test compile as the dependencies of the feature variant are missing on the test compile classpath!
Here is my current setup in build.gradle:
apply plugin: 'java'
apply plugin: 'java-library'
apply plugin: 'maven-publish'
sourceCompatibility = 1.8
java {
registerFeature('oSupport') {
usingSourceSet(sourceSets.main)
}
}
dependencies {
api 'my.compile:dep-a:1.0.0'
implementation 'my.runtime:dep-i:1.0.0'
oSupportApi 'my.optional:dep-o:1.0.0'
}
Let's assume there is a class O available from my.optional:dep-o. If I import O in any class in src/main/java it works perfectly. Also the dependencies are exported right to Maven (using gradle generatePomFileForMavenJavaPublication, see the dependencies from the generated pom.xml below). But any test in src/test/java using class O will not compile (import my.optional.O; creates error: package my.optional does not exist)
<dependencies>
<dependency>
<groupId>my.compile</groupId>
<artifactId>dep-a</artifactId>
<version>1.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>my.rintime</groupId>
<artifactId>dep-r</artifactId>
<version>1.0.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>my.optional</groupId>
<artifactId>dep-0</artifactId>
<version>1.0.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
</dependencies>
How to solve this? I know I could have used the nebula.optional-base plugin instead of the buildin Gradle feature variant but I would prefer the new gradle builtin support for optional dependencies instead.
PS: I use Java 8 and Gradle 5.6.2
This looks like a bug when the feature source set uses the main source set. Can you report on https://github.com/gradle/gradle/issues?
In the meantime, this should fix it:
configurations {
testCompileClasspath.extendsFrom(oSupportApi)
testRuntimeClasspath.extendsFrom(oSupportApi)
testRuntimeClasspath.extendsFrom(oSupportImplementation)
}
Really weird, I agree with #melix this seems to be a Gradle bug.
The following will fix it but should not be needed, imho:
dependencies {
api 'my.compile:dep-a:1.0.0'
implementation 'my.runtime:dep-i:1.0.0'
oSupportApi 'my.optional:dep-o:1.0.0'
testImplementation(project(":${project.name}")) {
capabilities {
requireCapability("${project.group}:${project.name}-o-support")
}
}
}
For this simplified setup with only one feature dependency could be replaced by testImplementation 'my.optional:dep-o:1.0.0' but for a general larger dependency list this approch avoids repetition of the dependencies as the extendsFrom solution of #melix.

Gradle 5: BOM dependencies are not written to pom file

I'm trying to use a BOM to build project A with Gradle 5. The pom file that's created does not correctly contain the BOM or the dependencies coming from it (see below). Moreover, Trying to build project B that depends on A fails on project A's pom.
When working with DependencyManagementPlugin (i.e. Not using Gradle 5 native support), everything works:
apply plugin:
io.spring.gradle.dependencymanagement.DependencyManagementPlugin
dependencyManagement {
imports {
mavenBom 'myGroup:infra-bom:1.0.+'
}
}
Creates this in project A's pom in a dependencyManagement block:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>myGroup</groupId>
<artifactId>infra-bom</artifactId>
<version>1.0.25</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
Trying to make it work with Gradle 5 isn't so lucky:
dependencies {
compile platform ('myGroup:infra-bom:1.0.+')
...
...
}
gradle dependencies shows correct versions from the BOM, but it creates this in project A's pom in the existing dependencies block:
<dependency>
<groupId>myGroup</groupId>
<artifactId>infra-bom</artifactId>
<version>null</version> // note the null here
<scope>compile</scope>
</dependency>
Which fails builds trying to use it.
Am I correctly using Gradle 5 native support for BOM? What does it include?

Publish BOM (as pom.xml) using gradle plugin java-platform

I am setting up a project specific BOM that will "inherit" definitions from other BOMs (available as pom.xml) and also define own managed dependendies.
I tried the following (as stated in the java-platform docs) in my build.gradle.kts:
plugins {
`java-platform`
`maven-publish`
}
dependencies {
constraints {
api(platform("org.camunda.bpm:camunda-bom:${Versions.camunda}"))
}
}
publishing {
publications {
create<MavenPublication>("camunda-bom") {
from(components["javaPlatform"])
}
}
}
But when I do gradle publishToMavenLocal and check the resulting pom.xml in .m2/repositories it looks like:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.camunda.bpm</groupId>
<artifactId>camunda-bom</artifactId>
<version>7.10.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
Which will not work because the syntax for importing poms should be
...
<type>pom</type>
<scope>import</scope>
...
How can I publish a valid BOM as pom.xml with gradle (using version 5.3.1)?
You are defining the BOM as a constraint, but that is most likely not what you want to do.
A constraint on a platform will just say that if that dependency enters the graph elsewhere it should use the platform part of it and the version recommendation from the constraint.
If you expect that constraints of that BOM to be visible to the consumers of your platform, then you need to add the BOM as a platform dependency by doing something like:
javaPlatform {
allowDependencies()
}
dependencies {
api(platform("org.camunda.bpm:camunda-bom:${Versions.camunda}"))
}
Then this will be properly published as an inlined BOM in Maven.

Add plugin dependency in grails

I am trying to add dependency of a plugin into my grails application, but it doesnot have any plugins in grails repo. It can be added to maven project as :
<dependency>
<groupId>com.plaid</groupId>
<artifactId>plaid-java</artifactId>
<version>0.2.12</version>
</dependency>
As my project is also maven based. How do i add this plugin into my project.
P.S. : IT cannot be added in plugins and dependencies since there is no grails plugin associated with that.
Any help is appreciated.
You can use the create-pom org.mycompany to create your pom.xml file to make grails read the pom.xml you need to set in BuildConfig.groovy this code
grails.project.dependency.resolution = {
/*YOUR CONFIG*/
pom true
repositories {
/*YOUR RESPOSITORIES*/
}
}
Then you need to add your dependency in this pom.xml
You can see the official doc. in this link
We can add dependency for any plugin in grails under dependencies{} in BuildConfig.groovy as:
<groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>
For your case, the equivalent for:
<dependency>
<groupId>com.plaid</groupId>
<artifactId>plaid-java</artifactId>
<version>0.2.12</version>
</dependency>
is:
dependencies{
compile "com.plaid:plaid-java:0.2.12"
}
For more you can have a look into http://docs.grails.org/2.3.1/guide/conf.html

Resources