Publishing JARs to Bintray with Maven and SBT

Page content

Update 26.03.2023: In February 2021, Bintray was shut down. This post still may be useful from the point of view of artifact publishing in Maven and SBT.

Many developers are interested in making their JVM artifacts (e.g. libraries) available for others. Probably, the simplest way to do this is to publish an artifact to Bintray, which gives free hosting for publicly available artifacts. Also, some teams would like to have private repositories for their shared JARs. In this case, Bintray can help as well.

In this post:

  1. Setting up a Bintray repository.
  2. Publishing JARs of a Maven project to Bintray, including sources, Javadoc and tests.
  3. Publishing JARs of an SBT project to Bintray + sbt-bintray plugin.

All the code used in this project is available in bintray-hello-world Github repository.

Simple Maven project

Let’s create a rather simple Maven project, which then we will publish to Bintray. If you want to publish an existing project, align accordingly.

I will use archetypes to generate the project skeleton (if you are not familiar with Maven archetypes, check Introduction to Archetypes page):

$ mvn archetype:generate \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DgroupId=me.ivanyu.bintrayhelloworld \
  -DartifactId=bintray-hello-world-java \
  -Dversion=1.0

Note the artifact ID bintray-hello-world-java, we will use it later.

It would be nice to provide some additional information in pom.xml, particularly the information about organization, licenses, SCM (source control management) and developers:

<organization>
	<name>me.ivanyu.bintrayhelloworld</name>
	<url>https://github.com/ivanyu/bintray-hello-world</url>
</organization>
<licenses>
	<license>
		<name>Apache License, Version 2.0</name>
		<url>https://www.apache.org/licenses/LICENSE-2.0</url>
		<distribution>repo</distribution>
	</license>
</licenses>
<scm>
	<connection>
		scm:git:git://github.com/ivanyu/bintray-hello-world.git
	</connection>
	<url>
		https://github.com/ivanyu/bintray-hello-world
	</url>
</scm>
<developers>
	<developer>
		<id>ivanyu</id>
		<name>Ivan Yurchenko</name>
		<email>[email protected]</email>
	</developer>
</developers>

Now, let’s add a very simple class to this project:

package me.ivanyu.bintrayhelloworld;

public class BintrayHelloWorldJava
{
    public static void say()
    {
        System.out.println("[Java] Hello World from Bintray!");
    }
}

Now we want to use this class in another project (or let other developers use it easily). To do so, we can publish a JAR file made from this project to Bintray.

Bintray preparations

In order to upload a JAR file to Bintray, we need to make some preparations:

  1. We need to create a repository, which is a container of artifacts of a particular type, e.g. Maven, Docker, NPM, Debian package files (Maven in our case).
  2. We need to create a package inside the repository, which is the logical representation of our artifact and its versions.

First off, log in to Bintray (you can do this with a Github account or in other ways). Then, on the home screen click “Add New Repository”:

Bintray - Create New Repository

On the next screen, enter the details of the repository. Two of them are essential: Name (I will use bintray-hello-world-repo) and Type (must be Maven).

Bintray - New Repository details

The repository has been created and you can access it now. On the repository screen https://bintray.com/ivanyu/bintray-hello-world-repo in my case) there is the list of packages (none for now) and the button to create a package, click it:

Bintray - Add Package

The next screen is for the details of the new package. One is important for us here, Name. I made it the same as the artifact ID, which is bintray-hello-world-java.

Bintray - New Package Details

After creating of the package it can be accessed (the link is https://bintray.com/ivanyu/bintray-hello-world-repo/bintray-hello-world-java in my case).

The Bintray repository and the package in it are now created, and we can upload our artifact with Maven.

A note on jCenter

jCenter is a public Maven repository provided by Bintray, analogous to Maven Central. You can easily add you package to it by clicking on “Include My Package” on its page.

A note on GPG signing

Bintray allows users to sign their uploaded artifacts using GPG with its own private key, or with a private key provided by the user. Signing artifacts is a good practice (and it is mandatory if you want to automatically transfer your artifacts to Maven Central). Description of this process is out of the scope of this post, but it is quite straightforward and is described in the documentation.

Publishing with Maven

We need to configure our project to enable Maven to publish the artifact created by it to Bintray. It is easy to do, just a tiny modification of pom.xml is needed. If you click on “Set me up!” button on the package page and go to “Uploading” → “Deploying with Maven”, you will see distributionManagement that needs to be added to the project definition in pom.xml. Also, there will be server settings to add to settings.xml. settings.xml is a Maven settings file, you can read more about it on Settings Reference page. password is your Bintray API key that can be found in the profile edit page.

After doing adding this data, you can try to publish the artifact:

$ mvn deploy

If everything is successful, you will see the newly uploaded version on the package page in Bintray.

Maven uses maven-release-plugin for publishing JARs (enabled by default). Once I faced a situation in which the default version of this plugin did not work well with Bintray (other times it was quite fine). A message like Failed to deploy artifacts: Could not find artifact ... is an indication of this problem. Changing the version of the plugin to 2.4.2 helped me:

<build>
	<plugins>
		<plugin>
			<artifactId>maven-release-plugin</artifactId>
			<version>2.4.2</version>
		</plugin>
	</plugins>
</build>

Moreover, you may want to publish sources and Javadoc JARs along with the main JAR. To do so, maven-source-plugin and/or maven-javadoc-plugin need to be configured. Add these lines to pom.xml:

<build>
    <plugins>
        <plugin>
            <artifactId>maven-source-plugin</artifactId>
            <executions>
                <execution>
                    <id>attach-sources</id>
                    <phase>package</phase>
                    <goals><goal>jar-no-fork</goal></goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <artifactId>maven-javadoc-plugin</artifactId>
            <executions>
                <execution>
                    <id>attach-javadocs</id>
                    <phase>package</phase>
                    <goals><goal>jar</goal></goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Another thing one might want to publish is a JAR with test files. maven-jar-plugin is what needs to be configured in this case:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <executions>
        <execution>
            <goals><goal>test-jar</goal></goals>
        </execution>
    </executions>
</plugin>

Using the published artifact

Now the artifact is in Bintray and is accessible for other projects. The example of an application that uses our artifact is here. Let’s recreate it. To add the artifact to a project, first add repositories section to the project definition in pom.xml:

<repositories>
    <repository>
        <id>bintray-ivanyu-bintray-hello-world-repo</id>
        <url>http://dl.bintray.com/ivanyu/bintray-hello-world-repo</url>
    </repository>
</repositories>

And then add a dependency:

<dependencies>
    <dependency>
        <groupId>me.ivanyu.bintrayhelloworld</groupId>
        <artifactId>bintray-hello-world-java</artifactId>
        <version>1.0</version>
    </dependency>
</dependencies>

Now, everything is ready (refresh project definition after modifying pom.xml if you are using an IDE) and we can try to use BintrayHelloWorldJava class:

BintrayHelloWorldJava.say();

The output will be as expected:

[Java] Hello World from Bintray!

You can find a more sophisticated repository configuration (you may need it if you are developing a Maven plugin, for example) by clicking the same “Set me up!” button on the package page and going to “Downloading”.

Publishing with SBT

SBT is a default Scala build tool. As well as Maven, it is capable of publishing artifacts to Bintray. Let me show you how to do this.

First, let’s create a new SBT project. Start from a very simple build.sbt:

organization := "me.ivanyu.bintrayhelloworld"
name := "bintray-hello-world-scala"

version := "1.0"

scalaVersion := "2.12.3"

licenses := List(
  ("Apache License, Version 2.0",
    url("https://www.apache.org/licenses/LICENSE-2.0"))
)
homepage := Some(url("https://github.com/ivanyu/bintray-hello-world"))

pomExtra :=
  <scm>
    <connection>
      scm:git:git://github.com/ivanyu/bintray-hello-world.git
    </connection>
    <url>
      https://github.com/ivanyu/bintray-hello-world
    </url>
  </scm>
  <developers>
    <developer>
      <id>ivanyu</id>
      <name>Ivan Yurchenko</name>
      <email>ivan0yurchenko@gmail.com</email>
    </developer>
  </developers>

I included the additional information the same as in the Maven project. This information will be transferred to the output pom.xml.

Then add BintrayHelloWorldScala object, analogous to BintrayHelloWorldJava:

package me.ivanyu.bintrayhelloworld

object BintrayHelloWorldScala {
  def say(): Unit = {
    println("[Scala] Hello World from Bintray!")
  }
}

Create a file .credentials in the SBT configuration directory (~/.sbt/.credentials) with the following content:

realm=Bintray API Realm
host=api.bintray.com
user=<username>
password=<api_key>

And now let’s modify build.sbt by adding the following lines:

publishTo := Some(
  "bintray" at
    "https://api.bintray.com/maven/ivanyu/" +
      "bintray-hello-world-repo/bintray-hello-world-scala/;publish=1")
credentials += Credentials(Path.userHome / ".sbt" / ".credentials")
publishMavenStyle := true

Now we can publish:

$ sbt publish

In contrast to Maven, SBT publishes sources and Javadoc JARs by default. To alter this behaviour, packagedArtifacts option exists. We can filter out artifacts we don’t want to be published:

packagedArtifacts in publish ~= { m =>
  val classifiersToExclude = Set(
    Artifact.SourceClassifier, 
    Artifact.DocClassifier
  )
  m.filter { case (art, _) =>
    art.classifier.forall(c => !classifiersToExclude.contains(c))
  }
}

The same way as Maven, SBT doesn’t include the test JAR by default. If you want to do this, you need to set:

publishArtifact in Test := true

sbt-bintray

SBT has a convenient plugin to work with Bintray: sbt-bintray. I am not going to describe how to use it, because it has a great README.