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.

 

Leave a Reply

Your email address will not be published. Required fields are marked *