and a buildfile I will code
and when it’s done and tested
to Ant and Maven I’ll say “no!”
Lately, one of my projects at work has been to switch our odd little Buildenstein’s Monster build scripts from a toxic stew that includes Ant (shudder) over to a pure Gradle design.
Gradle is a neat little tool. If Ant is insipid, annoying Justin Beiber and Maven is stodgy, mannered inflexible Bach, then Gradle is some sort of free jazz like Eric Dolphy that is sort of irritating, but you can still (occasionally grudgingly) admire the freedom and brilliance behind its freedom, flexibility and deviation from the norm.
So far, the project has been a rousing success. We’ve had to work through a lot of edge cases in places where Gradle’s behavior is just sort of odd and funky (I’ll write about those in the future!). The IDE support also is not nearly as good as Maven’s. While IntelliJ IDEA seems to leverage Maven’s limited set of rather shitty functionality perfectly, its Gradle support is less than inspiring (it’s often a lot quicker to use the Gradle tasks from the command line than from the IDE).
One thing that I do miss from Maven is its concept of a
provided scope. Essentially, this means that a project requires a certain dependency at compile time, but it should not be included in packaging or distribution.
This is particularly important when deploying a project to an environment that has an existing implementation of that dependency, or when the dependency is an interface that relies on an external implementation. This is the case for the Java Servlet API and Hibernate, among other things. (There is also an
optional scope in Maven, which I’ve never used, but surprise, users want this in Gradle too!)
Unfortunately, for Java programmers, this scope (
providedCompile) is only available for the
war plugin, not the Java plugin. This is actually a fairly serious omission, as all of the hair pulling and clothing tearing over at the going-on-five-year-old, heavily-upvoted JIRA issue requesting this feature and associated GitHub pull request show.
Indeed, a Google search for just the JIRA issue name reveals absolutely tons of
build.gradle files that implement the various not-quite-satisfactory workarounds for the lack of a proper provided scope while praying one day for a satisfactory resolution to the issue (I wonder how many buildfiles out there do this without referencing the issue name!).
The odd thing is that the last time this was raised on the
gradle-dev mailing list, it was met with the sound of crickets; not a single bite.
One thing I hate is boilerplate code, and all of these various hacks to add this functionality are basically boilerplate code, because literally every Java project that I have ever done has needed a scope for compile-time dependencies that shouldn’t be packaged.
The Gradle team has rightfully underscored the importance of not blindly including everything that Maven has without thought, but at the same time there has been little thought or discussion put towards providing this very basic, widely-used piece of functionality, All the while, the votes on the issue grow and users implement one or more of these cheesy workarounds, adding to their legacy code burden while there is already a pull request for the functionality.
Long story short: WTF?
EDIT: Lest I come across as unhelpful, here I’ll link to some of the better solutions to the Gradle team’s oversight:
- the Spring
propdeps-plugin: I know, I know, Spring. Amirite? No need to worry though, since this is just a Gradle plugin that provides the
provideddependency scopes, you won’t have to worry about including a gigabyte of transitive dependencies for simple functionality, like when you include anything Spring with your Java code.
- The best provided answer from the Gradle Forums: Notice that the Gradle developer who marked it ‘answered’ made no attempt to clarify or vet either of the solutions proposed.
- A further elaboration of the solution above. This is what I myself do until the Gradle team gets its act together.