If you still do not know what Gradle is
, then you can read about it in the previous two reviews:
- Gradle: Better Way To Build
- Gradle: Tasks Are Code
Not so long ago, the Hibernate Core
assembly was transferred from Maven to Gradle. To which the information community responded ambiguously
. I want to bring to your attention the translation of an article
on the migration of the Hibernate assembly. The article reveals the reasons for making such a decision, describes the advantages of Gradle and the problems with Maven2. Further narration is conducted on behalf of Steve Ebersole.
Many have asked me to write down the reasons why I want to move the Hibernate build from Maven to Gradle, and here I will list them. If you first encounter Gradle, it makes sense to review the review
. First of all, I want to emphasize that the purpose of this article is not “hit - crash - Maven” and not a direct comparison of Gradle with Maven. It’s just a way to tell the world about the problems and frustrations I’ve faced in 2.5+ years of using Maven to build Hiberbnate. In many cases, the reason is that the agreements used in Maven are inconsistent with how I imagine the Hibernate build. Some items from the list
compiled by Paul are only relevant for Hibernate (this list is also worth a look). It is also a way to explain why I preferred Gradle to other new build tools (Buildr, SBT, etc.). By the way, there is a wiki comparison of Gradle and Maven, but it is pretty outdated in many parts. Especially when it comes to Gradle.
Here are the problems (in chronological order rather than “in importance”) that I encountered in Maven:
- Maven does not support multi-module assemblies. It is argued that it supports, but this is not entirely accurate. To be precise, it supports the side of a group of independent projects . What is the difference? For example, take Hibernate. We have a set of modules that we assemble. Modules exist solely for the purpose of separating dependencies according to the functions used. Not using ehcache for caching? No problem, do not use the hibernate-ehcache module and ehcache will not be in your dependencies. We are not going to deliver these modules separately. Then why do we need to set the project version again and again (in all modules)? Here is an example of how maven complicates the simple. And the consequences are felt when, for example, I want to make a release. I have to manually make sure that the versions match in many different places (and don't even start about the release plugin)
- Okay, since I started about the release plugin. It is generally useless. I could get him to work more or less decently on small projects, but with Hibernate he almost always “fell”. Worse, you have to wait 30-40-60 minutes to find out that it will not work, then correct what he didn’t like (if you managed to find out), and launch it on a new one. In the end, we just gave up . (By the way, a friend just noticed that Jason van Zyl, dropped the release plugin in the seventh circle of hell, and that it will be replaced with “something new”)
- Hibernate-core - the main artifact. Hibernate-Annotations depend on it. Maven knows this. Well, why then I can't just go to the hibernate-annotations directory and run the 'maven compile' so that the hibernate-core is automatically built too? (hint: see item 1) In any case: `cd hibernate-core; mvn install; cd ../hibernate-annotations; mvn compile`- no gate in any way. The assembly tool must understand this itself after I have overcome so many obstacles, explaining to him the nature of these dependencies.
- One artifact on the project. I know this is a good rule. But Good Rules are rarely Absolute Truths. And for example, this Maven restriction forced us to take tests for the hibernate-core outside of the hibernate-core. Because we needed hibernate-testing, which depends on hibernate-core and sets the overall test runtime environment and is used in most other modules (we also wanted to make it available to users). And now we constantly have commits breaking tests, because developers (including me) forget to run tests because they are in some other, completely separate module. Yes, basically this is the problem of attention to detail, but shouldn't the assembly tool help in solving such issues instead of creating them? Well, one source directory and one directory of compiled classes per project. See http // in.relation.to / Bloggers / SimultaneouslySupportingJDBC3AndJDBC4WithMaven
- I, personally, can not stand the concept of combining "inherited pom data" and "module aggregation" in one file. This is a terrible thought. Many maven developers agree with me and helped develop a scheme in which Hibernate spreads “inherited pom data” to ./parent/pom.xml, and “module aggregation” to ./pom.xml. Well, maven supports it ... well, almost perfectly: it almost supports. The problem is that many plugins do not support this, and small, intricate problems begin. Why then distribute it at all? As I said, I do not think the union is correct. But why not step over the "right" and do it differently, because Does Maven work differently? The problem is in the settings after the initial checkout. You cannot assemble a module until its parent. But if the parent is an aggregator, then the only way to assemble the module is to install the entire project (or know the keys of the maven commands and disable recursion)
- At the very beginning, 2.5 years ago, I had to deal with our build DocBook. Christian, with his work on building DocBook using Ant in Hibernate, set the bar for many open-source Java projects. I had thoughts on how to improve this, using the concept of dependency management to download the right components as needed. The problem is that in order to do something similar in Maven you will have to write a plugin. You can’t "just throw a script, and then, if it turns out to be useful, I will pack it for others" (I understand that now it is to some extent possible with the help of GMaven, etc., but then it wasn’t) So I had to write jDocBook plugin and a few more. And with all of them there were problems. This is the only time I will directly compare Gradle and Maven, because Gradle "hit the bull's eye." Writing plugines in Gradle (I've already written 2 fairly large ones) is very nice. In a sense, this is not easy due to the lack of instructions on how to do this correctly, but the API and the features provided are simply amazing (and it’s not that Maven has the documentation for the "right plugin").
- Many users would like the build scripts to be configured to interact with the JBoss maven repository. It is quite logical: the assembly should work out of the box. But in Maven this cannot be done because the pom file used for the build will also be used for installation in the repository. And the majority of repositories (including JBoss and Maven Central) check that pom-files do not contain repository settings. So, instead of setting up scripts, we have to maintain the wiki and docbook and send users to the documentation.
- Running Hibernate tests on top of several databases is almost impossible through the IDE, in IntelliJ, at least using integration. The problem is in profiles and how integration interacts with them (in terms of filtering resources)
So, it's time to start looking for a better way to build Hibernate. Yes, Maven3 loomed on the horizon. Yes, it adds some “script support”, but this is more of a thingies. As far as I know, it just allows you to customize everything the same way in a different way. Therefore, I began to learn Gradle among other "DSL, build-by-convention" tools. (By the way, this thing is called Polyglot Maven and, according to a friend, Jason van Zyl stated that it will be removed and replaced with something else).
- The first and main advantage was the ability to create scripts for those parts of the assembly that are too difficult to describe in terms of “build by convention”. I liked this mixture: the best of both worlds is at your disposal.
- Faced with difficulties accessing information from other modules during assembly [using Maven2 - approx. lane.], I realized that the ability to write a brute force assembly modules using closures in many cases is simply a "gift of God." As well as the way to configure the default settings for all subprojects in the main gradle script is a masterpiece that far surpasses the concept of inheritance in Maven.
- Overall flexibility in the build and directory settings as I need it, without having to follow the limitations of the build system - that's fine
- The whole concept of the build process in Gradle is much cleaner, imho. In Gradle, you can not only define dependencies between modules, but also incredibly flexible description of dependencies on tasks, modules, directories, etc. For example, in Gradle we can already say that one module depends on the compiled classes, and not on the result (jar) of the other. Think about it. Very, very flexible. And useful!
- Each project or module may have several Source Set. "Source set" sets a set of source directories, a set of target directories, directories with resources, etc ... With this, for example, you can make the option of parallel support and testing JDBC3 / JDBC4 exactly as I wanted (see in.relation .to / Bloggers / SimultaneouslySupportingJDBC3AndJDBC4WithMaven )
- I don’t know what this is related to, but it’s so nice to think, “How am I going to do this?” Instead of “What options will the assembly system leave me?”
- Incremental build is great. Like this? She understands when something has changed, and when - no, and when parts of the assembly are actually needed. This is built into the plugins. The task determines the input and output, and Gradle uses this information to determine if the task should be started, because its input has changed, and whether the task has updated its output and therefore you need to run the tasks that depend on it. As a result, subsequent assemblies are very fast.
- Gradle's ability to publish artifacts in the maven repositories and generate accurate POMs is not only unique, but was also an important argument for making the transition decision. I may have complaints about building Hibernate with Maven, but the ability to create and use artifacts in a unified way is extremely necessary. In general, Gradle is able to generate a POM based on the information it has. And if not, you can simply describe additional parameters in the closure for configuring the POM. This is about flexibility.
- Generate IDE projects. This was another important argument. Most Hibernate developers use Eclipse or IntelliJ. Personally, I spend most of my time in the IDE: I write code, run tests, draw up documentation. I was not going to go by complicating the work in the IDE. Gradle has been able to create projects for Eclipse for quite some time. Recently there was an opportunity to generate projects and under IntelliJ. For her, they say, a gradle integration is being developed, similar to maven