Publishing jar in Gradle - java

I've been reading about publishing jar in the Gradle manual page (section 7.2.4).
The following code is provided:
uploadArchives {
repositories{
flatDir{
dirs 'repos'
}
}
}
I added that piece of code in my build script but there is no repos dir was created in my project-root directory after gradle build was executed. What does it actual do? Is there a documentation for uploadArchive and the others methods?

As the section 7.2.4. Publishing the JAR file, in the mentioned docs suggests, the file is not uploaded by the build but by the task uploadArchives.
To publish the JAR file, run gradle uploadArchives.
Further in the documentation there are the chapters 8.6. Publishing artifacts (with an example how to publish to ivy and maven (Example 8.8, 8.9)) and 52.4. Publishing artifacts.
The task is of type Upload, where one can delve deeper for how the task is working.

Related

How to deploy 100s of jars in Jfrog Artifactory

I was in the process of converting java projects build system from Ant to Maven and there are literally 700+ dependency jar files lying in a folder without any version or package information.
I was able to figure out maven co-ordinates for 400+ of those jar files using it's hash. So for the remaining 300+ jar files I am thinking of uploading it directly to a local repo in Artifactory and then generate maven co-ordinates automatically.
As far as i have explored the only way to achieve this is to deploy/upload every jar file manually via Artifactory UI with Deploy as Maven Artifact option enabled to generate co-ordinates automatically but this is a very time consuming process (I want to do this for 300+ files).
is there any other efficient way to do it?
I see two ways to achieve what you want, unfortunately none is available "out of the box"...
Use the command line client to upload each JAR file to Artifactory.
The main command to upload is:
jfrog rt upload foo.jar maven-local-repo
See https://www.jfrog.com/confluence/display/CLI/CLI+for+JFrog+Artifactory for more details
Use a bash script to loop on the JAR files, and for each file, upload it to a separate location, generate a short pom (from a sample pom and some sed to replace groupId and artifactId with the filename) and upload it next to the JAR file.
As Artifactory provides this option over its webapp, create a Selenium client that loops on each JAR file, connects to the Artifactory UI, and uploads each file using the "Generate default POM" option.
See https://www.jfrog.com/confluence/display/JFROG/Deploying+Artifacts#DeployingArtifacts-DeployingMavenArtifacts
I'm sure you already figured out a solution, but for anyone else who has to do something similar I ended up just using gradle to do it for me. I created a bare gradle project and with the following build.gradle. It collects all the jars from the directory specified and loops through them and creates publications for each. We wanted to use the sub-folder structure as the groupId so there's a bit of logic to format that in there.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4.21.0"
}
}
apply plugin: 'java'
apply plugin: 'maven-publish'
apply plugin: "com.jfrog.artifactory"
version = '0.2021.0'
ext.thirdPartyLib = fileTree(dir: "$rootDir/../extrajars", include: ['**/*.jar'])
publishing {
publications {
thirdPartyLib.each{ jar->
def fbase = jar.name.minus(".jar")
"$fbase"(MavenPublication) {
artifact jar
artifactId fbase
//the following was to use the folder structure as the groupId
def path = jar.path.minus("\\" + jar.name)
path = path.replaceAll("\\\\", ".")
path = path.replaceAll("c:/pathtoDirectory", "")
groupId = path
}
}
}
}
artifactory {
contextUrl = 'http://yourArtifactoryUrl'
publish {
repository {
repoKey='yourRepo'
username='username'
password='password'
}
defaults {
thirdPartyLib.each{ jar->
def fbase = jar.name.minus(".jar")
publications( fbase )
}
}
}
}

How to make gradle download dependencies without actually building things

On a new environment gradle build takes quite a while because all dependencies have to be downloaded.
Is there a way to only download dependencies in order to speed up the following build?
That way we could for example already prefill a CI build environment.
Edit: Updated for Gradle 6+.
Some notes:
This new approach downloads jars into a folder, and then deletes the folder. So the result of having the jars in the Gradle cache is a side-effect.
It currently uses jars configured for the main source-set but could be generalized.
Even though it is neither efficient nor elegant, it can be useful if you actually want the jars (and transitive dependencies): simply comment-out the deletion of the runtime folder.
This solution can be handy when you want the jars (and transitive dependencies), as you simply have to comment-out deleting the folder.
Consider this build.gradle (as an arbitrary, concrete example):
apply plugin: 'java'
dependencies {
implementation 'org.apache.commons:commons-io:1.3.2'
implementation 'org.kie.modules:org-apache-commons-lang3:6.2.0.Beta2'
}
repositories {
jcenter()
}
task getDeps(type: Copy) {
from sourceSets.main.runtimeClasspath
into 'runtime/'
doFirst {
ant.delete(dir: 'runtime')
ant.mkdir(dir: 'runtime')
}
doLast {
ant.delete(dir: 'runtime')
}
}
Example run:
$ find /Users/measter/.gradle/caches -name "commons-io*1.3.2.jar"
$ gradle getDeps
$ find /Users/measter/.gradle/caches -name "commons-io*1.3.2.jar"
/Users/measter/.gradle/caches/modules-2/files-2.1/commons-io/commons-io/1.3.2/[snip]/commons-io-1.3.2.jar
I've found ./gradlew dependencies (as suggested by this user) to be very handy for Docker builds.
You can create a custom task that resolves all the configurations( in doing so, it will also download the dependencies without building the project)
task downloadDependencies {
doLast {
configurations.findAll{it.canBeResolved}.each{it.resolve()}
}
}
Run command ./gradlew downloadDependencies
My answer will favor the gradle plugins and built-in tasks.
I would use "gradle assemble" in the command-line.
It is a minor version of "gradle build".
This way, you may reduce the time of your preparations before running or building anything.
Check the link bellow for the documentation:
https://docs.gradle.org/current/userguide/java_plugin.html#lifecycle_tasks
In general, what is my recipe when I clone a new repository:
-gradle assemble
-do some coding
-gradle run (and basically test until done)
-gradle build (to make distributable files)
note: this last step may have adicional configurations for .jar files as outputs (depends on you).

Maven-publish gradle plugin skips the version

I have gradle multi-module project configured with kotlin-script. I'd like to add publishing to maven repository and I found maven-publish plugin for it. But it seems to skip the version configured for each project:
MyProject/build.gradle.kts:
subprojects {
apply {
plugin("maven-publish")
}
configure<PublishingExtension>() {
publications {
repositories { ... }
create<MavenPublication>("myPublication") {
from(components.getByName("java"))
logger.lifecycle("test: ${project.group} ${project.name} ${project.version}")
}
}
MyProject/subproject1/build.gradle.kts:
version = "1.0.0-SNAPSHOT"
gradle publish output:
test: my.project subproject1 unspecified
artifact file does not exist: '.../MyProject/subproject1/build/libs/subproject1.jar'
File subproject1.jar doesn't exist, but subproject1-1.0.0-SNAPSHOT.jar does. How to make gradle get the correct version of module?
I found a similar problem while using the maven-publish plugin:
I was trying to set the repository URL depending on project version as described in the gradle docs here and this answer.
But I found the version always resolved to (as in the question) as the default (un-set) value: unspecified.
So I guess those documentation examples are for a project's build.gradle and not a general gradle script.
Anyway, I believe the problem is due to the timing of the execution of the blocks in the gradle script. The project.version could not be accessed where I wanted it. So I ended up passing a parameter to the gradlew command with the -Pparameter flag.
Gradle has a configuration and then an execution stage.
Refer to documentation:
https://docs.gradle.org/current/userguide/build_lifecycle.html
https://www.oreilly.com/library/view/gradle-beyond-the/9781449373801/ch03.html
and an apparently similar problem, https://discuss.gradle.org/t/maven-publication-closure-is-evaluated-too-early/19911
About your problem, it may be the same as I have described, or perhaps the reason is simpler:
Looking at the structure of your gradle file, it does not appear to match the hierarchy specified in the maven-publish documentation. In particular, repositories {} block should be at the same level as publications {}, not inside of it.
Possibly related:
Gradle maven publish plugin config has reference to dynamically created gradle task
Gradle shouldRunAfter not available for a task

Using Gradle with native dependencies

I am trying to use Sigar in a Gradle project. Sigar distribution is by default provided with 2 types of files:
a JAR that contains classes
some native files (.so, dylib, .dll)
My purpose is to repackage these files so that I can use them as dependencies deployed and downloaded on-demand from a personal Maven repository.
My first try was to define dependencies as files in order to check that my application is working as expected before to repackage. Below is the Gradle code I used for my first test that works:
dependencies {
compile files("${rootDir}/lib/sigar/sigar.jar")
runtime fileTree(dir: "${rootDir}/lib/sigar/", exclude: "*.jar")
}
Then, I have repackaged Sigar native files into a JAR and renamed the other one to match rules for maven artifacts since I want to deploy them in a Maven repository. Below is what I get:
sigar-1.6.4.jar (contains .class files)
sigar-1.6.4-native.jar (contains .dylib, .so, and .dll files at the root)
The next step was to deploy these files in my custom repository. Then, I have updated my build.gradle as follows:
dependencies {
compile 'sigar:sigar:1.6.4'
runtime 'sigar:sigar:1.6.4:native'
}
Unfortunately, when I do a gradle clean build, new dependencies are fetched but native libraries can no longer be found at runtime since now I get the following exception:
Error thrown in postRegister method: rethrowing <java.lang.UnsatisfiedLinkError: org.hyperic.sigar.Sigar.getCpuInfoList()[Lorg/hyperic/sigar/CpuInfo;>
Consequently, I am looking for a solution to fetch and to link native files to my Java app like for other dependencies. Any advice, comment, suggestion, help, solution, etc. are welcome ;)
A solution is to define a new gradle configuration that unzips JAR files at the desired location:
project.ext.set('nativeLibsDir', "$buildDir/libs/natives")
configurations {
nativeBundle
}
dependencies {
nativeBundle 'sigar:sigar:1.6.4:native'
}
task extractNativeBundle(type: Sync) {
from {
configurations.nativeBundle.collect { zipTree(it) }
}
into file(project.nativeLibsDir)
}
dist.dependsOn extractNativeBundle
Then, this location must be put in java.library.path for tasks that depend on native libraries:
systemProperty "java.library.path", project.nativeLibsDir

How to make a .jar out from an Android Studio project

I'm using AndroidStudio and I have this project as shown:
What is inside the blue circle is myLib. myLib also needs to use an external lib that is inside the red circle, and an apache package (green circle).
So I want to make this whole thing become a single .jar, so I can use it in another projects.
A step-by-step guide would be really appreciated, I'm a beginner in the developer world.
Thanks!
Open build.gradle for library project
Write two tasks in build.gradle -- deleteJar and createJar and add rule createJar.dependsOn(deleteJar, build)
The code from above:
task deleteJar(type: Delete) {
delete 'libs/jars/logmanagementlib.jar'
}
task createJar(type: Copy) {
from('build/intermediates/bundles/release/')
into('libs/jars/')
include('classes.jar')
rename('classes.jar', 'logmanagementlib.jar')
}
createJar.dependsOn(deleteJar, build)
Expand gradle panel from right and open all tasks under yourlibrary->others. You will see two new tasks there -- createJar and deleteJar
Double click on createJar
Once the task run successfully, get your generated jar from path mentioned in createJar task i.e. libs/xxxx.jar
copy the newly generated jar into your required project's lib folder-->right click-->select "add as library"
If you set up the code as a plain Java module in Gradle, then it's really easy to have Gradle give you a jar file with the contents. That jar file will have only your code, not the other Apache libraries it depends on. I'd recommend distributing it this way; it's a little weird to bundle dependencies inside your library, and it's more normal for users of those libraries to have to include those dependencies on their own (because otherwise there are collisions of those projects are already linking copies of the library, perhaps of different versions). What's more, you avoid potential licensing problems around redistributing other people's code if you were to publish your library.
Take the code that also needs to be compiled to a jar, and move it to a separate plain Java module in Android Studio:
File menu > New Module... > Java Library
Set up the library, Java package name, and class names in the wizard. (If you don't want it to create a class for you, you can just delete it once the module is created)
In your Android code, set up a dependency on the new module so it can use the code in your new library:
File > Project Structure > Modules > (your Android Module) > Dependencies > + > Module dependency. See the screenshot below:
Choose your module from the list in the dialog that comes up:
Hopefully your project should be building normally now. After you do a build, a jar file for your Java library will be placed in the build/libs directory in your module's directory. If you want to build the jar file by hand, you can run its jar build file task from the Gradle window:
In the Android Studio IDE, access the "Run Anything bar" by:
CTRL+CTRL +gradle CreateFullJarRelease+ENTER
After that you'll find your artefact in this folder in your project
Build > Intermediates > Full_jar > Release > CreateFullJarRelease > full.jar
OR
Gradle has already a Task for that, in the gradle side-menu, under the other folder.
Then scroll down to createFullJarRelease and click it.
After that you'll find your artefact in this folder in your project
Build > Intermediates > Full_jar > Release > CreateFullJarRelease > full.jar
Simply add this to your java module's build.gradle. It will include dependent libraries in archive.
mainClassName = "com.company.application.Main"
jar {
manifest {
attributes "Main-Class": "$mainClassName"
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
This will result in [module_name]/build/libs/[module_name].jar file.
task deleteJar(type: Delete) {
delete 'libs/mylibrary.jar'
}
task exportjar(type: Copy) {
from('build/intermediates/compile_library_classes/release/')
into('libs/')
include('classes.jar')
rename('classes.jar', 'mylibrary.jar')
}
exportjar.dependsOn(deleteJar, build)
Go to Gradle tab in Android Studio , then select library project .
Then go to Tasks
Then go to Other
Double click on bundleReleaseaar
You can find your .aar files under your_module/build/outputs/aar/your-release.aar
I had a supplement;
In the new version Android Studio(for me is: Android Studio Arctic Fox | 2020.3.1 Patch 3
Build #AI-203.7717.56.2031.7784292, built on October 1, 2021)
In gradle panel, it has no task in default.
Go to the Android Studio ---Settings--Experimental--Gradle tab, uncheck"Do not build Gradle task list during Gradle sync", then click File--Sync project with Gradle files, then the task appeared in the Gradle Panel.
Then follow the answer: https://stackoverflow.com/a/52681317/4065069
In case of this accepted answer not working for you
Use this
task createJar(type: Copy) {
from('build/intermediates/packaged-classes/release/')
into('libs/jars/')
include('classes.jar')
rename('classes.jar', 'plugin.jar')
}
Instead of this
task createJar(type: Copy) {
from('build/intermediates/bundles/release/')
into('libs/jars/')
include('classes.jar')
rename('classes.jar', 'logmanagementlib.jar')
}
the way i found was to find the project compiler output (project structure > project).
then find the complied folder of the module you wish to turn to a jar,
compress it with zip and change the extension of the output from zip to jar.
.jar file will be automatically generate when u compile/run your application.
You can find your class.jar file from root_folder/app/build/intermediates/bundles/debug
If you use
apply plugin: 'com.android.library'
You can convert .aar -> .jar
If you run a gradle task from AndroidStudio[More]
assembleRelease
//or
bundleReleaseAar
or via terminal
./gradlew <moduleName>:assembleRelease
//or
./gradlew <moduleName>:bundleReleaseAar
then you will able to find .aar in
<project_path>/build/outputs/aar/<module_name>.aar
//if you do not see it try to remove this folder and repeat the command
.aar[About] file is a zip file with aar extension that is why you can replace .aar with .zip or run
unzip "<path_to/module_name>.aar"

Categories

Resources