How to convert a Maven project to Gradle in real life

Ming
4 min readSep 16, 2022

--

Because gradle init isn't enough.

Gradle uses an elephant as its logo. Photo by Magda Ehlers from Pexels

Motivation. Nearly all tutorials online will tell you to run gradle init , which will detect Maven's pom.xml and convert some basic configurations to Gradle's build.gradle. That's sweet, but you almost always need more than that. The complexity roots from the fact that both Maven and Gradle are very modularized, and their plugins aren't interchangeable.

Scope. This post serves as a catalog of unofficial (but de facto) Gradle equivalents of Maven plugins I’ve collected. When it’s not readily available elsewhere, I’ll also provide sample configurations for both build tools in each case, putting them equivalent as much as possible.

Maven, as an Apache project, uses a feather as its logo. Photo by Evie Shaffer from Pexels.

Code Formatter, Contract Scaffolding, and Version Bumping

Well-maintained software may provide a Maven plugin and a Gradle one simultaneously. For example, the code formatter Spotless has a Maven edition and a Gradle edition. Across both build tools, Spotless recognizes the same set of configurations, so all you need to do is to translate some XML to Groovy — a trivial task.

Screenshot from its repo.

For other plugins, things can be tough. If you are lucky, you can find unofficial ports, wrappers, or mimickers of the Maven plugin in the Gradle world. As an example, Swagger Codegen maintains an official plugin for Maven, while Gradle users would have to settle with an unofficial wrapper. (For usage of this plugin itself, see the section below, “Generate code from OpenAPI contracts”.)

Even for what you’d consider “basic” features, this is often still the case. For example, to bump version numbers at release time, Maven offers an official plugin (namely, the Maven Release Plugin), but Gradle users have to rely on a third-party developer (namely, gradle-release):

While you’d define the version in pom.xml with Maven, Gradle puts it in a separate file, gradle.properties:

# Managed by the plugin `gradle-release`. Edit with caution.
version=0.0.1-SNAPSHOT

Note for CI users: gradle-release needs to know which remote branch it can push the version-bumping commit to. Therefore, when checking out the code, remember to check out to a branch (on contrast to a Detached Head).

Publishing to a Maven Repository

Releasing and publishing often go hands in hands. Since you’re migrating a project from Maven, chances are that you are publishing its artifacts to a Maven Repository.

Maven’s use of a feather as its logo led me to envision a Maven Repository as a pile of feather. Photo by Nadejda Bostanova from Pexels.

With Maven, you would run mvn deploy for uploading your artifact to a remote MR or mvn install for the local. These two commands are realized by two separate plugins, Maven Deploy Plugin and Maven Install Plugin). On the Gradle side, however, one plugin provides both, confusingly named Maven Publish Plugin. Equivalents of those two commands are gradle publish and gradle publishToMavenLocal, respectively.

Defining your own Maven Repository server

Your organization may have an internal Maven Repository. In that case, your pom.xml might have been configured with a Distribution Management tag:

On the Gradle land, this can be written more succinctly:

Authenticating for Maven Repository

Pardon the cliche of using a stock photo of a key to represent the idea of authentication. Photo by PhotoMIX Company on Pexels.

Most likely, your Maven Repository requires authentication. In your settings.xml, you may find a <server /> section with username and password (encrypted, of course):

Good news is that Gradle can simply read your Maven settings.xml for the credentials. Just add the plugin maven-repo-auth:

This plugin will read from ~/.m2/settings.xml > settings > servers for the <server /> whose <id /> matches repositories > maven > name.

Generate code from OpenAPI contracts

If you’re building API servers in 2022, you may be practicing Contract-First Development, with your contract adhering to OpenAPI Specification.

In the Maven world, to generate code from the contract, a popular choice is the Swagger Codegen Maven plugin. Your pom.xml would be configured like this (taken from the official README file):

The Gradle equivalent is the Gradle Swagger Generator Plugin:

Configurations for Swagger Codegen are defined under <configOptions /> in Maven and in additionalProperties in Gradle. To ease the migration between the two, put Swagger Codegen configurations in a separate file. (In my examples above, that's the swagger-config.json.) Both the Maven plugin and the Gradle plugin can read it.

Parting Words

You may be surprised to learn how differently the two build tools grow their ecosystems. For many features, Maven boasts official plugins, whereas Gradle users rely on community efforts. Migrating from Maven to Gradle is no easy work.

That being said, if the two were identical, why bother with the migration at all? Pick your poison. As commonly said, software engineering is about making tradeoffs. The best we can do is to make everybody’s lives easier by summarizing and sharing the field knowledge, as this article — and my whole blog — is striving to.

--

--