
If you have been working with Java for some time, you might have come across some scenarios where you wanted to publish source code as a jar file so it could be reused in other projects. In this scenario, there are mainly two parts: first, we need to build a jar file, and second, we need to publish the public or private repository, like Maven, GitHub packages, etc. As part of this article, let’s try to understand how we can build library jars with Gradle and publish the same to GitHub packages.
How to build Jar
There are different kinds of jar files, depending on the packaging technique—
- Skinny — Contains only the business logic, literally whatever you typed in the code editor.
- Thin — In addition to Skinny Jar contents, it contains direct dependency as well. But it won’t contain anything related to the application runtime (example: application server).
- Hollow — It is the exact opposite of a thin jar. It contains everything related to the application runtime but doesn’t contain the app itself. Basically, it contains a pre-packaged “app server” on which apps can be deployed at a later point in time. This packaging technique is very similar to traditional Java EE app servers.
- Fat/Uber — It’s a self-sufficient jar that contains everything that needs to run the application on its own.

As part of this article, we’ll try to understand how we can build Thin jars with Gradle.
import java.text.SimpleDateFormat
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
manifest {
attributes(
'Implementation-Vendor': project.group,
'Implementation-Title': project.name,
'Implementation-Version': project.version,
'Built-By': System.properties['user.name'],
'Created-By': "Gradle ${gradle.gradleVersion}",
'Build-Timestamp': new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date()),
'Build-Jdk': "${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']})",
'Build-OS': "${System.properties['os.name']} ${System.properties['os.arch']} ${System.properties['os.version']}"
)
}
from {
configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) }
}
exclude 'META-INF/*.RSA'
exclude 'META-INF/*.SF'
exclude 'META-INF/*.DSA'
}
We can add the above code snippet to build.gradle and we can run ./gradlew jar to build the jar file.
Note: Here we added a couple of attributes to the manifest, these attributes are optional, but it’s good practice to have them.
Publish Jar to GitHub Packages
Once we have built the jar file, we can publish it to a public or private library repository like Maven or GitHub packages so that it can be reused in other projects. But as part of this article, let’s try to understand how we can publish it to GitHub Packages —
apply plugin: 'maven-publish'
publishing {
repositories {
maven {
name = "GitHubPackages"
url = "https://maven.pkg.github.com/<organization/username>/<repository name>"
credentials {
username = "<username>" // System.getenv("USERNAME")
password = "<password>" // System.getenv("PASSWORD")
}
}
}
publications {
gpr(MavenPublication) {
from components.java
groupId = project.group
artifactId = project.name
version = project.version
}
}
}
We can add the above code snippet to build.gradle, and we can run ./gradlew publishToMavenLocal to publish the library to the local Maven repository (m2 cache), generally it presents at <user home folder>/.m2/repository. Once it’s published to the local m2 cache, we can verify the package by using it in some other project locally. Once we are happy with the result, we can run ./gradlew publish to publish the library to GitHub packages.
Publish Jar to GitHub Packages using GitHub Action
In the above code snippet, we published the jar from the local system using the user’s username and password or token. But if you are already using GitHub actions for CI/CD, we can use the workflow to publish the jar to GitHub packages without using personal credentials.
# build-and-publish.yml
name: build and publish
on:
push:
branches: [ main ]
tags:
- 'v*.*.*' # We will publish new version for tag which follows 'v*.*.*' format
env:
SERVICE_NAME: hello-world
jobs:
verification:
runs-on: ubuntu-22.04
steps:
- name: Checkout local repository
uses: actions/checkout@v3
with:
path: $/$
- uses: actions/setup-java@v3
with:
distribution: 'temurin' # Here we are using temurin java distribution but can be customized depends on the requirement
java-version: '17' # Here we are using java 17 but can be customized depends on the requirement
cache: 'gradle' # Here are enabling gradle cache to cache gradle wrappers, dependencies etc. It can be disabled by simply removing the line
- name: Run all tests
run: ./gradlew clean check --no-daemon
working-directory: $/$/
determine_should_publish_new_version: # Publish new version for new tags
runs-on: ubuntu-22.04
outputs:
PUBLISH_NEW_VERSION: $
steps:
- name: Checkout local repository
uses: actions/checkout@v3
- name: Determine should publish docker image
id: determine_should_publish_new_version
run: |
PUBLISH_NEW_VERSION=false
if [[ $(git tag --points-at HEAD) != '' ]]; then
PUBLISH_NEW_VERSION=true
fi
echo "PUBLISH_NEW_VERSION=${PUBLISH_NEW_VERSION}" >> $GITHUB_OUTPUT
publish-jar:
runs-on: ubuntu-22.04
needs: [ determine_should_publish_new_version, verification ]
if: $
permissions:
contents: read
packages: write
steps:
- name: Checkout local repository
uses: actions/checkout@v3
with:
path: $/$
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
cache: 'gradle'
- name: Publish jar
run: ./gradlew publish --no-daemon
working-directory: $/$/
env:
GITHUB_TOKEN: $
apply plugin: 'maven-publish'
publishing {
repositories {
maven {
name = "GitHubPackages"
url = "https://maven.pkg.github.com/<organization/username>/<repository name>"
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
}
}
}
publications {
gpr(MavenPublication) {
from components.java
groupId = project.group
artifactId = project.name
version = project.version
}
}
}
Using the above code snippets, we’ll be able to publish the jar to GitHub packages using the GitHub action.
Conclusion
As part of this article, we have built Thin Jar and published the same to GitHub packages. But similar concepts can be used to build other types of jar files and publish them to other repositories, like Maven Central.
PS: I hope you’ve enjoyed it, and if you’ve found it useful, please feel free to share it with others or leave a comment.
Originally posted on medium.com.