Possible to write build.gradle in pure Java..?

A very strength of Gradle is that you can extend the DSL. For example the Android plugin is adding many top level language elements to the Gradle DSL to provide a very concise and powerful spec for Android builds.

In Maven you can not extend the DSL. That makes it easy to provide a content assist. But it makes it very weak when it comes to extensibility. It is only extensible on a Maven plugin level which is the equivalent of a Gradle task.

Actually that project looks really well made. I will test it thoroughly on the weekend. Maybe I just use Jerkar for ALL of my project and Gradle for the small Android parts. Thanks for the tip!

I honestly don’t think so. As @Schalk_Cronje was pointing out in his other email, a key job of a Gradle build script is to be a highly expressive and readable spec for a build. For example:

android {
    defaultConfig {
        minSdkVersion 8
        versionCode 10
    }

    productFlavors {
        flavor1 {
            packageName "com.example.flavor1" + substring
            versionCode 20
        }

        flavor2 {
            packageName "com.example.flavor2"
            minSdkVersion 14
        }
    }
}

You can’t do this with plain Java. There would be a lot of ugly boiler plate code in the build script. So we either could have created an external DSL. Which would have its own beauty but is challenging once you want to do some small manipulations (like String manipulations or concatenations). The other approach was to create an internal DSL based on a language that is DSL friendly (Groovy, JRuby, Jython). That was our approach. We picked Groovy as our DSL language as it is the easiest to pick up for Java developers. We did not want to have multiple variations of the DSL (let’s say Groovy and Ruby) to avoid fragmentation. But we are only talking about the pure DSL layer. The Gradle core is written in Java and for Plugins you can use any language you want. Although, to be fair, often the usage of script plugins is very convenient and for those you have to use Groovy.

Again, the most important target group for the build script is not the build author but the developer trying to quickly understand the spec how this project is build. I’d rather compromise on the convenience to create a spec than to understand it. Of course we want to eventually not compromise on either.

2 Likes

I think one cannot deny the many benefits of Gradle. Still there are so many downsides if you are no Gradle developer: http://samskivert.com/blog/2015/03/gradle-difficutles

My biggest beef with Ant, Maven and Gradle is that everything is very black box. If you run into a problem it is very hard for a beginner to solve it. Gradle has the benefit that Google/Android endorsed it and that MANY of the problems people can be found on the web.
Still, I often find myself sitting on a small Gradle script for hours in order to find a solution. I am at a point where I would directly write against a well documented Java-API, with all the nice IDE support, compiler benefits, debugging and all the source-code running my build at my finger tips. And if the build-script is twice as verbose as Gradle, so be it.

Well
maybe it impossible to write a build-tool less then 90% hate :smiley:

P.S.: not removing that task keyword with Gradle 2.0 is unforgivable! This confused the heck out of me for a long time!

This is a very interesting idea. Java 8 definitely opens up new opportunities. Although I would love to see more features in Java to support DSL’s. It would be absolutely possible to make Java very DSL friendly if it were prioritized.

As long as you are not working on the DSL level.

I will think more about this and I’m looking forward to discussing this further.

Hopefully Buildship will provide a set of IDE integration features (completion, “javadoc”, debugging, et cetera) that will satisfy these needs.

I totally disagree with that. It states very clearly that a new task will be added to the script.

I am glad you like the idea. I thought about this for a while not related to Gradle but building JVM based less verbose static or dynamic languages like Scala, Groovy, Xtend, etc.
Those existing JVM-languages have one thing in common: they all target the JVM by adhering to the .class file standard.

My idea is to build a slew of new languages that can all be mapped to valid (and very readable) .java source files. I described in my first post how this should happen and how IDE integration would look like. Especially since Java8 such a mapping could be quite simple and still powerful.

In the end you would have different mappings that “show” .java code in a Python-like syntax or Scala-like syntax or Groovy-like syntax. The syntax wouldn’t be 100% since you don’t want the mapping to be over-complicated.

I think this would make especially sense on a team level where developers could choose what mapping-flavor they use in their IDE and they always have the chance to switch back to pure Java. Languages like Groovy have a problem with adoption. It is all nice and good but many people, especially teams, don’t like to do a full switch to something like Groovy.

The whole concept is actually more involved and I only scratched the surface
but I think you get my point. One would need to do further experimentation to see how this concept fairs in a real-world implementation.

I am not sure, but I think you misunderstand. There is the task keyword and the task method call.

The task keyword is achieved (if you want to call it that) by black compiler magic via DefinitionScriptTransformer. It’s not really valid Groovy and scares the hell out of every beginner who learns Groovy and then sees Gradle scripts that mess with his knowledge :smile:

In my opinion there should be ONE way to do this:

task.create(name: “someTask”, type: JavaExec) {}

Adding a task to the collection of tasks should be explicit. Groovy (and by consequence Gradle) allows you to do the same thing in many ways. Too many ways. But then I am also against having two ways to create a String in Java (String a = new String(“a”); AND String a = “a”;). That’s just unacceptable :wink:

It may be a matter of taste but the difference is not big at all using fluent API.
You can mimic the hierarchy style as

public Android android {
    return Android.of(AndroidConfig.of()
	        .minVersion(8)
		.versionCode(10))
	    .and("flavor1", Flavor.of()
	        .packageName("com.example.flavor1" + substring)
		.version(20))
	    .and("flavor2", Flavor.of()
	        .packageName("com.example.flavor2")
		.minSdkVersion(10));
}

Or you can embrace a more regular style (much more readable/maintenable in my sense) that all Java developper will understand and edit quite easily :

AndroiConf defaultConf() {
    return AndroidConfig.of().minVersion(8).versionCode(10);
}

Flavor flavor1() {
    return Flavor.of("com.example.flavor1" + substring).version(20);
}
    	
Flavor flavor2() {
     return Flavor.of("com.example.flavor2").minSdkVersion(10);
}
    	
Android android() {
    return Android.of(defaultConf()).and(flavor1()).and(flavor2());
}

Or more compact with the help of Lombok:

Android android() {
    val defaultConf = AndroidConf.of()
                     .minVersion(8).versionCode(10);
    val flavor1 = Flavor.of("com.example.flavor1" + substring)
                  .version(20);
    val flavor2 = Flavor.of("com.example.flavor2")
                  .minSdkVersion(10);
    return Android.of(defaultConf).and("flavor1", flavor1).and("flavor2", flavor2);
} 

Not sure that the least scripts are less concise and readable than Groovy one, but probably easier to edit thanks to the full force of IDE (javadoc, code completion, code navigation,
)

Look at what you can do with Jerkar Project for example.

Your examples are showing established patterns to model DSL’s in Java. For me in the context of builds they are significantly less readable and full of noise compared to a proper DSL. I’m not in favor of such an approach.

1 Like

What do you mean exactly by “in build context” ?
In most situation the people maintaining the build file are the same that code the project. So maintaining a Java build file has a very low margin cost on Java project cause it is just another Java class to maintain among dozens, hundreds or thousands.

Using a ‘foreign’ language and use dedicated tooling to avoid Java noise only on the build file seems really overkill to me.
If a team really fell Java too noisy (and it is arguable) then it might write the entire project in Groovy, 
 so Groovy would make sense to write the build script :smiley: (as I would expect to use Javascript for building Javascript projects, Scala for Scala, Ruby for ruby,
)

Beside, the above Java DSL is not so ugly when displayed in an IDE with syntax color, and Javadoc behind a hover/click on each DSL element.

The “build context” you are meaning, is it a context where people who maintain the build script are not the ones who develops the project ? A context where the build is supposed to be read by non Java developer ? It might happen but in my experience it is rarely the case.

I mean a DSL for the domain of builds. Which is a complex domain. Which is also multi-language domain, e.g. we have more and more C/C++ projects being build with Gradle.

Often this is not the case.

I think we are talking about very different things here. There is the role of Java in implementing your business logic (Gradle is written in Java). We are very happy with it. Then there is the role of using Java as the foundation for your specification language for your build. It is a completely different domain. It is not plain Java vs plain Groovy. It is the suitability to create an (internal) DSL on top of it. We are also talking here about things like AST transforms. For example with the buildscript block in Gradle you can add dependencies to your build script itself in the same file where you define your build.

In my opinion those days are gone. Modern software stacks are multi-language. You want one build system for all of with which you can model a coherent, highly automated and integrated build process. That is a key reason why many organizations are using Gradle.

It still is a very different experience. To give you an example from another domain. The DSL is a key reason why I found Spock by far the best mocking and testing framework out there. You are so much more productive with Spock because of that.

Obviously it would not be hard to implement Java based build scripts with Gradle. But we think it is better to solve the current short coming when it comes to tooling than to switch/offer a plain Java based build script language.

I have a lot of trouble getting used to the Gradle DSL. This is not becasue it’s base syntax is difficult, in fact, it is probably more concise and easier than anything possible in Maven POMs. The real reason of my difficulty is that I am knee-deep into basically programming Groovy/DSL - just because it is possible, and maybe trying to mimic maven and ant features in some ways.

The only improvement is probably not by starting to code in Java, but by allowing the existing ecosystem of tools within the plugins and base DSL to mature. Also what helps a lot is just letting go of the old ways, and trying to settle in with the new style. Still I am missing how simple it was to keep part of my configuration outside the project. Gradle allows to do the same (init.gradle), but unfortunately, you switch from the Project context to the Gradle context in doing so.

I don’t. I just prefer on build tool to build everything for me (as far that it is possible). This is all a matter of personal preference, but I do not want to be caught in a programming-language-must-be-the-build-tool trap. If the latter was the case, Maven would not have existed in the form it is today. Nor would have the Make set of build tools. Then there is the question of how many people like to use SBT to build Scala 


The fact that Gradle is based on a Groovy DSL should be irrelvant to the programming language(s) you are using to development your applications.

I always feel very restricted when using Gradle. It does the job if you do everything by convention and don’t need a lot of special things during your build. So if your build works with the Gradle build files being almost empty (full convention) you are blessed and Gradle is a blessing. If you need to be very flexible you end up coding in Groovy with a special taste of being tied to Gradle. It’s horrible to debug. I don’t think the makers of Gradle will ever understand.
I am curious how it was decided to use Groovy as Gradle DSL historically? The project/scope Gradle has today (with people expecting deep and perfect IDE integration) I wonder if they would have every chosen Groovy. Using Java as far as IDE integration and coding support or debugging goes can never be touched by Groovy even if they optimize it for another decade. A huge part of this is the nature of statically typed vs. dynamically typed.

1 Like

Well, as you said that’s a matter of taste.
But for project using Java on sever side and modern html5 stack (i.e es6/reactjs/webpack/
) you’ll hardly convince both team to use same build tool :slight_smile:

That is one of the main criticisms yielded against Maven. It works well if you play strictly by the rule book, but if you need somet5hing more flexible it is going to be painful. I am a bit surprised that you feel restricted. Given your comments I would think deflated would be more appropriate. However, moving on, the mantra with Gradle tends to be that once the build file becomes complex, you might have enough to farm it off to a plugin (or at least to the buildSrc folder). This leads me nicely to your next statement.

This is nothing new to build tools that use an internal DSL (i.e. a DSL based upon a programming language). Cons & SCons had this issue way before Gradle was even an embrio. So do contemporary build tools like Kobalt, Leiningen & SBT. The coice is usually between a restrictive DSL (Make & family, Maven, Ant etc.) or a more flexible one. In both cases, build tools are usually extendable via plugins, but the effort required to extend may vary. Gradle is excellent in the aspect of allowing quick experimentation, only extending later, where as something like Maven always requires one to write the neew plugin from the start, without easy experimenting with the build file. (Well, there a limited possibilities, but not nearly as flexible and quick as in Gradle).

Why was XML chosen as the build script style for both Ant & Maven? Most probably because XML was cool in those days in the Java world. Java pretty much supported XML from the beginning (at least from what I can remember, and not having used Java in the 90s). People understood XML. Wind the years forward and I am not going to give the correct answer here (I’ll leave that to @adammurdoch), but it was a time when Groovy was the most expressive and readable way to script the JVM. (It probably still is, but that is up for debate). Choices are made upon technology available and technology known.

END NOTE: There is a modified joke that goes: There are two kinds of build tools, those that people don’t get used and those that they complain about. The mere fact that opinions are being offered up here, is an indication that Gradle is being used bychoice even though people are finding shortcomings in Gradle that relates to the context they are working in and their own personal preferences (we sometimes refer the the latter as signature skills). ONe should not see Gradle as the end-all build-tool, but merely as an evolution in build-tools. It, with its mates like Kobalt & Leiningen, are a next-generation of build-tools beyond that of Maven. They also allow the software communities of the world to experiment with new ideas and new forms of expression and as such learn new ways of doing things. This will also lead into another generation of build tools, which would probably be here within the next 10 years. Exactly what they will look like we do not know. (If we knew we would already be using them).

1 Like

As a relative newcomer to Gradle (about a month and a half), I rather vehemently disagree with this. Admittedly my use-case is a bit different than most, I suppose. I am working on a replacement for a system that used nmake and an ancient proprietary version control system to build thousands of small projects (some java-based and some not) that were deployed in RPMs. RPMs are not a “native” container type in the Java based ecosystem.

My initial effort was attempted using Maven which I knew and had a love-hate relationship with. Although the Maven RPM plugin support is somewhat ahead of what the Gradle RPM plugin offers, I found it almost impossible to use the Maven plugin. At every corner, another obstacle was found, and another hacky workaround demanded by Maven’s heavy convention demands, requiring dozens of new lines of xml. When I showed what I had wrought, of which I was initially proud, to my teammates, I became embarrassed. Clearly, my work could not be possibly extended to thousands of small projects in any acceptable timeframe.

Once I made the choice to switch to Gradle, everything got better. My build scripts for individual gradle projects are maybe two orders of magnitude smaller than those for Maven. (True, I wrote plugins for Gradle which accounts for part of the script reduction, but plugin creation would have been much more difficult in Maven). Yes, I had (and still have) my groovy learning curve, and yes, I even agree with you that sometimes having one way to express something rather than five is a better way to go, but I’m getting used to it. Yes I hate that there are similar looking constructs that behave differently, and I’ve even complained about that here, but eventually, you get there. Things that had me scratching my head for hours if not days are now solved in minutes.

I have learned to live with the limited Eclipse support as well (improvements will be appreciated), but I long ago learned to live without Eclipse debugging and stepping though code in general, even when I am writing java, and I rarely use it. That is probably the main cause of our disagreement.

It was very easy to express my typical use cases in gradle plugins, and if I need to write more plugins, these will be easy as well. I just created a new plugin this morning in about fifteen minutes. When I demoed this system to my teammates they were extremely impressed and my embarrassment is gone.

1 Like

I think that once a build script goes beyond a very basic set of tasks and configurations, moving code into buildSrc and implementing them like regular code, outside of the DSL, or even in a separate plugin, makes the most sense. If you end up having a huge set of logic written inlined in the task and model definitions, it’ll be painful pretty much whatever tool you use.