Versionless gradle dependencies - java

When I do this
dependencies {
file('libs/something.jar')
}
I have something.jar in my distribution.
But, when I to push the dependency to remote repository (ivy or maven) and want to use it from there, gradle always adds a version postfix to the jar.
dependencies {
compile group: 'org.company', name: 'something', version: '1.0'
}
results in something-1.0.jar.
Even this
dependencies {
compile group: 'org.company', name: 'something'
}
results in something-.jar (note the dash).
Can I somehow prevent the repository dependency to have a version?
(My motivation is that the jar is a 3rd party jar, I don't want to have it in git repo but I also don't want its name to change.)

As you've said, you're ok with giving the artifact a version in the repository. You just don't want a version in the jar in your application. You could do
configurations {
something { transitive = false }
}
dependencies {
something 'org.company:something:1.0'
something 'org.company:something-else:1.0'
compile files(tasks['dummyTask'])
compile 'org.foo:some-normal-dep:1.1'
}
task copySomething(type:Copy) {
from configurations.something
into "$buildDir/something"
rename '(.+)-.+?\\.jar', '$1.jar'
}
task dummyTask {
dependsOn copySomething
inputs.dir "$buildDir/something"
outputs.files fileTree("$buildDir/something")
}
The main enabler for this is that Project.files(...) can accept a Task

Related

Using Eclipse NonNull annotations with multiple Gradle projects

We've been using the Eclipse #NonNull and #Nullable annotations in our code for a while.
We are now adding some Spring projects defined with Gradle to our system. These projects will share quite a bit of code with our standalone projects as well.
We are seeing a problem due the Eclipse annotations (being compile time checking) don't work when a Spring/Gradle project refers to the shared code via Gradle generated .jar file. Eclipse needs to have the source of the shared jar in order for the annotations to work. Attaching the source in the Eclipse project only works until you need to do a Gradle Refresh, as that rebuilds the eclipse .project and .classpath files.
It's also a problem that you have to explicitly rebuild the shared .jar each time you make a change to the shared code. It's not done automatically.
I haven't found a way to have the Spring/Gradle projects just use a 2nd source directory for the shared code, and not need to have the shared code as a generated .jar file.
Is there any good way to have shared code between multiple Gradle projects in Eclipse - without using an intermediate .jar file? (Or some other way to get the Eclipse annotations to work.)
Not really sure how to give a full example, as most of this is gradle and eclipse configuration.
Here are the Gradle config files: settings.gradle
pluginManagement {
repositories {
maven { url 'https://repo.spring.io/milestone' }
gradlePluginPortal()
}
}
rootProject.name = 'App1-Account-Manager'
and build.gradle
plugins {
id 'org.springframework.boot' version '2.5.0-RC1'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.efi'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.2'
implementation 'org.springframework.boot:spring-boot-starter-amqp'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.amqp:spring-rabbit-test'
implementation files('lib/eflow/eFlowClientApi.jar',
'lib/eflow/eFlowCryptography.jar',
'lib/eflow/json-simple-1.1.1.jar',
'lib/eflow/commons-codec-1.4.jar',
'lib/eflow/commons-io-2.6.jar',
'lib/eflow/commons-lang-2.6.jar',
'lib/eflow/commons-logging-1.2.jar',
'../App1-Commons/build/libs/App1-Commons-0.0.1-SNAPSHOT.jar'
)
implementation group: 'org.eclipse.jdt', name: 'org.eclipse.jdt.annotation', version: '2.1.100'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.7'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.security:spring-security-test'
}
test {
useJUnitPlatform()
}
App1-Commons is the project of shared code that multiple other projects depend on. That's where a bunch of the #NonNull annotations are.
I can set the App1-Account-Manager project to depend on the App1-Commons project in eclipse - but as soon as you run a Gradle Refresh, it looses that connection.
I'd prefer to just have the source from App1-Commons included in the App1-Account-Manager project - but I don't see how to configure Gradle to do that with Eclipse projects.
I think I found the solution. I need to add a SourceSets block to the build.gradle file like this:
sourceSets {
main {
java {
srcDir 'src/main/java'
srcDir '../App1-Commons/src/main/java'
}
}
}
And remove the reference to the App1-Commons jar file.

Multiple dependency versions with Gradle 5

I need to support 2 different versions of the same library (to support a legacy version), es4hadoop for Apache Spark.
Version 6.2.2(https://mvnrepository.com/artifact/org.elasticsearch/elasticsearch-spark-13_2.10/6.2.2)
Version 6.3.2 (https://mvnrepository.com/artifact/org.elasticsearch/elasticsearch-spark-13_2.10/6.3.2)
Both versions have same dependencies (scala-lang and Spark).
Not sure at all about the naming of that, but I would like something like:
implementation(group: 'org.elasticsearch', name: 'elasticsearch-spark-13_' + scalaVersion, version:'6.2.2') {
exclude group: "org.scala-lang"
}
implementation(group: 'org.elasticsearch', name: 'elasticsearch-spark-13_' + scalaVersion, version:'6.3.2') {
exclude group: "org.scala-lang"
relocate org.elasticsearch org.elasticsearch6 // ???
}
so I can use both new and old elasticsearch library, in the same project / JVM.
I know already it's possible to relocate lib with the shadowJar plugin, but is it possible to relocate a specific version?
Put one of the elasticsearch-spark dependencies into a subproject aa2 and relocate it. Then the other subproject aa1 can depend on aa2's shadow configuration.
// aa2/build.gradle
dependencies {
implementation 'org.elasticsearch:elasticsearch-spark-13_2.10:6.2.2'
}
shadowJar {
relocate "org.elasticsearch", "org.elasticsearch_v6_2_2"
}
// aa1/build.gradle
dependencies {
implementation 'org.elasticsearch:elasticsearch-spark-13_2.10:6.3.2'
implementation project(path: ':aa2', configuration: 'shadow')
}
You can now declare the same class in this way:
package com.github.chehsunliu.stackoverflow.q56332118;
import org.elasticsearch.spark.cfg.SparkSettings;
public class App {
public static void main(String[] args) {
System.out.println(SparkSettings.class);
System.out.println(org.elasticsearch_v6_2_2.spark.cfg.SparkSettings.class);
}
}
However, you should pay more attention to their transitive dependencies. You might also need to relocate them to make the direct dependencies work normally. Sometimes I will decompress the output JAR file and investigate these .class files to ensure the resolution correctness.
References
Minimal project: https://github.com/chehsunliu/stackoverflow/tree/main/gradle/q56332118
Decompiler https://java-decompiler.github.io/

Gradle custom plugin jar with dependencies

I'm trying to build a jar for a custom gradle plugin to be used by other gradle projects. I'm using java to write the plugin. I'm having a problem including dependencies in my jar. If I build the jar using the below build.gradle
plugins {
id 'groovy'
}
repositories{
mavenCentral()
}
dependencies {
compile gradleApi()
compile localGroovy()
compile 'com.google.guava:guava:27.0-jre'
testCompile 'junit:junit:4.12'
//compile 'org.apache.commons:commons-lang3:3.8.1'
}
group = 'com.mine'
version = '1.0'
I get a NoClassDefFound exception for guava classes when applying the plugin on a project. If I include a task to create a jar with dependencies like below in the build.gradle
jar {
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it)}
}
}
It says Plugin with Id 'my-plugin' not found. How do I include dependencies in a gradle plugin jar?
Your plugin project should be configured as a standalone Plugin project and then published to a maven repository, which will make dependencies resolution work; there is good documentation about writing custom plugin here, specially the following part : using Gradle plugin development plugin
There is also a good example of writing/publishing/consuming a custom Plugin in the Gradle examples here : https://github.com/gradle/gradle/tree/master/subprojects/docs/src/samples/plugins (see the two subprojects publishing and consuming )
And here is a working example with a plugin that has dependency on external library (commons-lang for example):
Plugin project
build.gradle
plugins {
id 'java-gradle-plugin'
id 'groovy'
id 'maven-publish'
}
group 'org.gradle.sample.plugin'
version '0.1'
// pugin metadata configuration
gradlePlugin {
plugins {
myplugin {
id = "org.gradle.sample.plugin.myplugin"
implementationClass = "org.gradle.sample.plugin.MyPlugin"
}
}
}
// publish to local maven repo for testing
publishing {
repositories {
maven {
url "../repos/maven-repo"
}
}
}
// repo for dependences resolution
repositories{
jcenter()
}
// dependencies of this plugin
dependencies {
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'
}
Plugin implementation : src/main/groovy/org/gradle/sample/plugin/MyPLugin.groovy
package org.gradle.sample.plugin
import org.apache.commons.lang3.StringUtils
import org.gradle.api.Plugin
import org.gradle.api.Project
class MyPlugin implements Plugin<Project> {
#Override
void apply(final Project project) {
println "Applying custom plugin... "
project.tasks.create('testPlugin'){
doLast{
println " custom plugin task executing."
println "Result: " + StringUtils.capitalize("stringtotest")
}
}
}
}
Build and publish this plugin ./gradlew publish : the plugin jar and "plugin marker artefacts" will be published to local maven repo in ../repos/maven-repo
Consumer project
build.gradle
plugins {
id 'java'
// import/apply your custom plugin
id 'org.gradle.sample.plugin.myplugin' version '0.1'
}
group 'org.gradle.sample.plugin'
version '0.1'
repositories{
maven {
url "../repos/maven-repo"
}
jcenter()
}
To test the plugin, try to execute the plugin task testPlugin
> Task :testPlugin
custom plugin task executing.
Result: Stringtotest
Sorry to add this as an answer but I don't have enough points to comment (yes it is a bit late in coming but I found this in a search and it came so close, maybe this will help someone else).
The answer by #M.Ricciuti is correct, just missing one file, namely a settings.gradle in the referencing project (not the plugin) directory:
pluginManagement {
repositories {
maven {
url '../repos/maven-repo'
}
gradlePluginPortal()
ivy {
url '../repos/ivy-repo'
}
}
}
Many thanks, I have tried many things that didn't work before finding this, even the examples by gradle didn't work (or more likely I didn't run them correctly). Anyway I merged what I saw in the answers with M. Ricciuti's answer and saw that file in the sample.
My complete project is at https://github.com/reddierocket/sampleGradlePlugin
The readme has instructions to run it. (Note I did not include the wrapper but I am using gradle version 5.3.1.)

How do I include a single dependency in my JAR with Gradle?

I'm starting with Gradle and I was wondering how do I include a single dependency (TeamSpeak API in my case) into my JAR so that it could be available at the runtime.
Here is a part of my build.gradle :
apply plugin: 'java'
compileJava {
sourceCompatibility = '1.8'
options.encoding = 'UTF-8'
}
jar {
manifest {
attributes 'Class-Path': '.......'
}
from {
* What should I put here ? *
}
}
dependencies {
compile group: 'org.hibernate', name: 'hibernate-core', version: '4.3.7.Final'
compile group: 'org.spigotmc', name: 'spigot', version: '1.8-R0.1-RELEASE'
// Many other dependencies, all available at runtime...
// This one isn't. So I need to include it into my JAR :
compile group: 'com.github.theholywaffle', name: 'teamspeak3-api', version: '+'
}
Thanks for your help :)
The easiest way is to start with a separate configuration for the dependencies you want to include. I know you only asked about a single jar but this solution will work if you add more dependencies to your new configuration. Maven has a well known name for this sort of thing called provided, so that is what we will use.
configurations {
provided
// Make compile extend from our provided configuration so that things added to bundled end up on the compile classpath
compile.extendsFrom(provided)
}
dependencies {
provided group: 'org.spigotmc', name: 'spigot', version: '1.8-R0.1-RELEASE'
}
jar {
// Include all of the jars from the bundled configuration in our jar
from configurations.provided.asFileTree.files.collect { zipTree(it) }
}
Using provided as the name of the configuration is also important because when the jar gets published, any dependencies you have in the providedconfiguration will show up as provided in the POM.xml that gets published with the JAR. Maven dependency resolvers will not pull down provided dependencies and users of your jar will not end up with duplicate copies of classes on the classpath. See Maven Dependency Scopes

How to publish programmatically manipulated (e.g. instrumented) jars in Gradle?

I have a multi-project build. Sub-project CoolApp depends on sub-project CrazyJar. Project CrazyJar has no sources: it uses a tool to perform byte code manipulation on an existing jar derived from non-Gradle project BigProject and wishes to publish the resulting manipulated jar to be depended on by CoolApp. It needs to publish this as a local Maven package.
Since it seems the "maven-publishing" plugin only supports "java" and "web" projects, I apply the "java" plugin to CrazyJar. But CrazyJar has no sources! I end up publishing an empty artifact. Is there any way I can mangle this to work as though it were a normal Java project? If not, anything else I might do?
Hmm, yeah, I misunderstood my problem slightly. Well, here was my solution anyway (based mostly off documentation for the "maven-publish" plugin):
Root project
subprojects {
repositories {
maven {
url "${rootDir}/repo"
}
}
}
CrazyJar project
apply plugin: "maven-publish"
...
task createCrazyJar(type: Exec) {
...
}
publish {
dependsOn "createCrazyJar"
}
publishing {
publications {
mavenJava(MavenPublication) {
artifact createCrazyJar.outputs.getFiles().getSingleFile()
}
}
repositories {
maven {
url project.repositories.maven.url
}
}
}
CoolApp project
dependencies {
compile group: "coolproject", name: "crazyjar", version: project("CrazyJar").version
}

Categories