Category Archives: maven

Why I converted a Gradle project to Maven

It may sound quirky, but I had finally HAD IT with a project I manage: Spring Web Services. There were several aspects of the build file that kept getting in my way.

Well, I was about to embark upon a critical change from which Gradle pushed me over the edge. To the point that not only did I convert to Maven, but ALSO moved the reference documentation from DocBook to Asciidoctor.

So what’s wrong with Gradle?

I know this is controversial, but I have worked with many projects. On the Spring team, it’s a common paradigm that if you need either a feature or a bug fix applied to some aspect of the portfolio, you check it out and submit a patch.

The community embraces this, and sometimes, if you really need something, the fastest route is to do it yourself.

Spring Framework, Spring Security, Spring Cloud Stream, Spring Session, Spring Session MongoDB, Spring Data Commons, blah blah blah. Just a handful of the projects I have dipped my toe in, some more than others.

Many use Maven, many use Gradle. I don’t mind Gradle for the occasional patch request. But when it came to an up-and-coming switch Spring Web Services had to make, Gradle wasn’t going to cut it.

Spring Web Services was going to create a new major release. We had supported 2.4 for a couple years, and 3.0 was about to get launched. This was the version where I could bump up the minimum to Java 8, Spring Framework 5, and other key 3rd party libraries.

That wasn’t the tricky part. The fact that we had to maintain the 2.4 branch at the same time, meant I needed a simpler build model.

Gradle comes loaded with a programming model that lets you declare things, and then hook in extra code to tailor things. And that is the problem!

Declarative vs. programmatic

Maven has this pattern of declaring what you want, and it goes and carries it out. You declare things like:

  • Artifact coordinates
  • Dependencies
  • Plugins

Because people frequently need to adjust settings for different scenarios, Maven supports the concept of profiles.

Gradle starts with the concept of a declarative build system as well. You can also declare:

  • Artifact coordinates
  • Dependencies
  • Plugins

But guess what? No first class support for profiles. Most people say, “no problem! Just code it.” Gradle uses Groovy, so you can write a little glue code, and BAM you have the concept of profiles.

Why do I need profiles? To make backwards compatibility maintainable, I always test each patch against the latest GA release of Spring Framework, as well as the latest snapshot release and the next major version. Each of these, captured in a separate profile, allows me to command my CI server to run every single patch across multiple versions of Spring Framework/Spring Security, and verify I’m not breaking anything.

Gluing this together with Groovy code was okay when I maintained a single branch. But migrating into maintaining two branches (master for 3.0 stuff and 2.x for the 2.4 stuff), that frankly wasn’t going to cut it. You see, Maven profiles are supported inside IntelliJ IDEA, but some glue code that emulates the same concept in Gradle doesn’t work AT ALL. It drives me to use the command line when my IDE should be supporting me.

This isn’t the only thing I’ve seen Gradle come short on where one must write code in their build file.

Frankly, I don’t WANT to write code there. That’s what I was able to do with Ant, and Ant drives one to spend too much time in the build file. Gradle is by no means as bad as Ant, but it seems a tad ant-ish.

Anything else?

Since you asked, there is another irritant. Gradle has plugins and that is great. Except that the blocks they add to your build file are at the global level. That means any construct you spy with settings inside it doesn’t identify the plugin they came from. You want to debug some piece of the build? You can’t jump to the plugin’s docs. You must first rummage around Google to determine which plugin is at hand.

To drive my point home, I’ve checked out projects where the developer built a handful of custom gradle plugins. That’s nice and handy, but it raises the need for me to READ every single plugin to know what’s happening.

Frankly, I’d prefer a block of XML, where the coordinates of the plugin AND its configuration details are RIGHT THERE. Maven may not offer the same magic of codability, but I fear that feature is shadowed by lack of discoverability.

Why the hate?

Okay, I know that Gradle is pretty cool out there. Many have been driven over the cliff by Maven. But to be honest, I haven’t seen enough payoff to warrant sticking with Gradle.

Since I could be wrong, feel free to dive into the comments and give me your pluses and minuses about Gradle vs. Maven!

Something Java should never do

I’ve been working on a pull request on Spring HATEOAS for six weeks. That’s right, six weeks. It was a community contribution, and there’s a lot to sift through. Yesterday morning, I was slated to conduct the first review with the project lead. But that wasn’t going to happen, because Java decided to do something Java should never do.

Maven wouldn’t build my project while IntelliJ IDEA would.

I was alerted to this issue Thursday morning when I created a “run all profiles” script and it wouldn’t work. Huh? Every time I’ve pushed an updated commit to Travis CI, it builds perfectly. That’s right, a CI server, running Maven, built my branch with ease. But my Mac would not.

This made no sense. This is something Java should never do! Java doesn’t work on Linux but fail on a Mac. It must be my machine, right? So I log onto my wife’s MacBook Air, update Java to the latest version, grab the source, and fire off Maven. BOOM! It breaks just the same.

So…here comes the online review with Ollie. I pronounce my inability to build the system. The man with twenty years professional experience, who has written four tech books and one tech video, who has been fighting this for twenty four hours, pleads with his manager for clues. Ollie grabs the branch, tries to build, and SPLAT. It doesn’t work. He goes through the same questions I do, and finds no answers.

We jump to our OTHER CI server, Bamboo, and he commands it to build my branch. It works. Perfectly.

Score so far: Three Macs – 0  Two Linux CI servers – 2

“Ollie, this is something Java should never do!” I scream into my Google Hangout. (Okay, maybe I didn’t scream.)

He nods along. The review is busted. We both flip to our daily standup Hangout, and Ollie’s first words are, “Greg, I know what you did.” Heh.

We wrap that meeting up, and I proceed to dig through every Stackoverflow article I can find on Lombok, maven-compiler-plugin, and Java 6. Talk about a nebulous combination. WIth enough evidence that this is Lombok’s fault, I open a ticket.

Fun day, given it’s my son’s last day of school for the year. I’m irritated at having to stop work to fetch him. My brain keeps churning the whole time. The second I get home, I have him go play. Anything to get back to my keyboard and keep trying options. I flip through a myriad of options for maven-compiler-plugin: memory, forked JDK, use Java 8, hand configure annotation processors. Nothing works.

My three-year-old is trying to climb up on me, and I push him to the side. “I must find the answer!” Time to pick up our 7-year-old arrives, and I dash off. After getting home, she is asking me to write LOGO code. “No sweetheart, I need to try something first.” I usually stop ANYTHING to help her, but I was too obsessed with this issue.

At this point, I start to De-lombok the code. Maybe if I can flip Lombok off. I get 90% of the code converted, and IT STILL WON’T BUILD! What could this possibly be? Every debug/verbose flag I activate still shows me nothing about what is actually breaking. Just some missing symbols followed a completely corrupted class.

Then I get a strange idea. A curious insight. What if the first class that Maven claims about, a nested static class, was made top level? I command IntelliJ to perform this refactoring. Poof, the error message changes. So I make the next nested static class in the list of errors top level as well.

BANG! Reading “[INFO] BUILD SUCCESS” makes my jaw drop.

I cancel all my changes, and build again. Same failure. I then strategically pick one nest static class, and move it. Everything suddenly works. What the…? This is something Java should never do.

Looking at the Jackson2HalModule (the predecessor to my work on Jackson2HalFormsModule), I count the number of nested static classes and compare to this one. The HAL parser has eight or nine, the new work has over twelve. Somehow, this enclosing class has TOO MANY NESTED STATIC CLASSES!

Not wanting to move everything into public classes, I rig up HalFormsSerializers and HalFormsDeserializers, and split up the nested static classes into these two “namespaces”. Everything is humming. This change is mind boggling. Because this is something Java should never do.

So what is happening? Still not sure, but it implies that Lombok’s annotation processor must scan every class looking for its annotations. If the class is too deep, the scanner breaks and doesn’t recover, hence causing any nested classes further on to fail. And somehow, this state is contingent on the platform, because it works jim dandy on Linux while failing on the Mac.

I copy all these details into the Lombok ticket I opened. I hope I shined a light on an issue perhaps the committers can pinpoint and fix. But for now, my PR is buffed up and reviewable again. And as I go to bed, I can finally sleep in peace, having slain another dragon in the realm of open source hacking.

 

Gradle or Maven? I really don’t care

The project I’m working on, Spring Data REST, recently rolled out a big update: they changed the build system from gradle to maven!

This kind of shocked me at first. I’ve been hearing that gradle is hip and cool and maven is old and stagnant. All hail gradle!

And yet, in just a few hours, I realized that I really didn’t care. I didn’t care because both gradle and maven are GREAT build tools. That automate the entire process. Since 99% of my time spent on a given project is in the source code and support scripts and NOT the build process, I don’t really care a lot about what build tool is in use.

I understand people run into issues with maven. If you try to deviate too much from the convention you will pay for it dearly. Guess what; it’s not that hard to follow the convention. It’s not a bad price to pay for being able to jump to other projects and see the same layout. It’s also handy that IntelliJ IDEA can easily suck in a multi-module, maven-based project without batting an eyelash.

What about gradle? It’s pretty neat as well. I sure enjoy updating the build system when needed without having to bear all the XML cognitive overload. Gradle’s groovy-based system is simpler to read. I appreciate that IntelliJ IDEA can also crack open a gradle-based app just as well.

But then again, it can run away. I’ve seen REALLY complex build systems (like the Spring Framework). It becomes an art to discern all the stuff involved to build that hunk of software. Why? Because Spring has a lot of stuff going on! No build system can make it super simple.

Pros and cons for each?

  • Gradle it easier to read. No XML overload. It’s easy to use, declarative, and comes with gobs of plugins. I have even had people tell me that crafting your own plugin is pretty easy. But it doesn’t have the concept of parent projects that can provide inheritable version numbers
  • Maven is widely adopted. Even when we wanted to primarily use gradle for Spring’s Getting Started Guides, we decided that maven support could not be ignored. Maven has more than one way to inherit a set of dependencies and properties. This feature is REALLY useful. Spring Boot leverages it widely, effectively declaring a stack of dependencies it uses.

Bottom line: either one of these are better than some ivy+ant solution. I have worked with ant in the past. It is so customizable, so detail oriented, so extensible, that you can ONLY interact with it at the low level. I don’t imagine IntelliJ IDEA being able to suck in an ant project and immediately fetch all it’s dependencies.

You are dragged down to that horrendous level of detail every time you want to dig into an ant-based build. Most of the time, when I interact with the build system, it’s because I need to roll some versions and upgrade things. Maybe add a new module. That’s easy.

In the end, trading in such detailed complexity has a huge productivity payoff. I have to use both because of the proliferation of projects, hence, it’s not a steep job for me to switch gears.

Putting your money where your mouth is

I like maven. There, I said it. Now where is my flame suit?

Last night at the Nashville Java User Group meeting, Kerry gave a good introductory presentation on maven. He talked about the pros and cons, and showed some things like phases, profiles, and parent/child projects. For those who had little to no experience with maven, it was a good introduction. Hopefully they will read more.

I jested afterwards that he should write a blog entry to generate traffic for his web site, because a discussion about maven is never luke warm. People come out either strongly for it or against it. I expressed this at last night’s meeting. Well, sitting here this morning and checking twitter, etc., I realized that I would be a bit of hypocrite if I wasn’t willing to put my money where my mouth was and write my own blog entry.

So here we go. I like maven for a handful of reasons:

  • consistent format of project layout
  • transitive dependency management
  • more plugins than I can imagine
  • declarative definition that supports convention over configuration
  • maven’s one-artifact-per-project promotes a better breakout of modules
Does maven have issues? Yes. What build system doesn’t?
Is it state-of-the-art? No. The XML can be wearying.
These seem to be the two key things that cause people to discard it and seek something else. I have seen this first hand. Instead of using maven, someone typically tries to replicate maven’s intentions using other technologies. If you are on a team where someone has built their own build system there is another dependency that can start to get in your way and come incredibly annoying: that person. Any issues with that build system require support of that person because there is not likely to be any documentation. I didn’t like this aspect, and when that person worked in a different time zone than me or was on vacation, it became detrimental to productivity on occasion.
So what about things like gradle? To tell you the truth, I am kind of excited about new technologies like gradle and sbt. They look very appealing, and I really like the idea of using groovy or scala instead of XML. XML is a strain to read, though for some reason, I find myself reading pom.xml files instead of using my IDE’s editor.
I guess being a command line junky, I prefer to work with the real file rather than a massaged presentation. Probably makes me sound like a dedicated emacs user. While I use vi a lot, I also edit a lot of code inside my IDE. Nothing beats the ability to highlight 200 lines inside my IDE and hit the comment key combo. I use both on equal footing, and it makes me feel like I’m versatile. But…I digress.
Back to the topic at hand: what about new build technologies like gradle? I think a critical feature of tools like gradle would be integration with maven. I understand this is in the core of it, so hopefully gradle will expand and become more mainstream. But right now, I haven’t adopted it.
Go and figure out what meets your needs. But take into consideration what happens when you hire more people. Will you be able to point them at standard documentation, or will you have to be on call to answer questions about your build system? It’s up to you. Just be aware that something like 85% of all java projects use maven. (Okay, I don’t remember the actual number, but according to a survey conducted by the Eclipse foundation, it is a HUGE majority like that). It’s one less impedance mismatch to deal with. Be sure to factor that into your TCO (total cost of ownership).
Whatever you choose, happy building!