Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Groovy for Domain-Specific Languages, Second Edition
Groovy for Domain-Specific Languages, Second Edition

Groovy for Domain-Specific Languages, Second Edition: Extend and enhance your Java applications with domain-specific scripting in Groovy

eBook
$27.98 $39.99
Paperback
$54.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

Groovy for Domain-Specific Languages, Second Edition

Chapter 1. Introduction to DSLs and Groovy

It has been over 10 years since my first contact with the Groovy language. The occasion was an introductory talk about Groovy at JavaOne in the Moscone Centre, San Francisco, by James Strachan, the creator of the Groovy language. Java itself was just 10 years old at that time and Groovy was one of the very first languages other than Java to run on the Java Virtual Machine (JVM).

Just this year, Java celebrated its twentieth birthday. In 2005, there were an estimated 3 million Java developers worldwide. Now, in 2015, Wikipedia estimates it as 11 million. The Groovy language has also taken off. There were an estimated 5 million downloads of Groovy in the last year alone. So what are the benefits of Groovy and why should you consider using it?

The Groovy project site at http://www.groovy-lang.org explains this better than I ever could with six major benefits:

  • A flat learning curve
  • Powerful features
  • Smooth Java integration
  • Domain-specific languages
  • A vibrant and rich ecosystem
  • The scripting and testing glue

In this book, we will cover all the key benefits of the Groovy language. The main focus, however, is on how Groovy supports the development of domain-specific languages through its metaprogramming features.

One of the big benefits of Groovy is how its dynamic features support the development of domain-specific languages (DSLs) or "mini languages", which we can run directly on the JVM alongside your existing Java code. Groovy DSLs integrate seamlessly into the Groovy language itself in such a way that it's not always apparent where the regular Groovy code stops and the DSL starts.

In fact, large parts of almost any Groovy application are written using Groovy-based DSLs. For instance, a new developer starting out with Groovy might assume that the builder code he uses to output some XML is a part of the core Groovy language. But it is, in fact, a mini internal DSL implemented using the Groovy metaprogramming features.

If you are an Android developer, the chances are you may have programmed in Groovy already. Since 2013, the build system in the Android SDK has been a tool called Gradle (http://www.gradle.org). Gradle is a Groovy-based DSL for dependency management and build automation.

Whether you are one of the 11 million existing Java developers, looking to add DSL features to you application, or you are an existing Groovy developer looking to improve your knowledge of DSL writing, metaobject programming or AST transformations, this book is intended for you.

By the end of this book, I hope that you will have the knowledge and the confidence to start building your own DSLs with Groovy, and be able to integrate them into your Java applications. To begin with, in this chapter, we will take some baby steps. This chapter will give you a brief background on DSLs and their usage. We will also dip a toe into the Groovy language, and briefly touch on the features of the language that distinguish it from Java and make it a great tool for developing DSLs on top of the Java platform.

DSL – a new name for an old idea

I've mentioned domain-specific language (DSL) several times now, so what does this really mean? The term "DSL" describes a programming language that is dedicated to a specific problem domain. The idea is not new. DSLs have been around for a long time. One of the most exciting features of Unix has always been its mini languages. These include a rich set of typesetting languages (troff, eqn, pic, and so on), shell tools (awk, sed, and so on), and software development tools (make, yacc, and lex).

The Java platform has a multitude of mini DSLs in the form of XML config files for configuration of everything from EJBs to web applications. In many JEE applications, Enterprise Java Beans (EJB) can be configured using an XML configuration file, ejb-jar.xml. While the ejb-jar.xml file is written in the general-purpose language XML, the contents of the file need to conform to a document type definition (DTD) or XML schema, which describes the valid structure of the file.

XML configuration files can be found across a wide range of libraries and frameworks. Spring is configured by using a spring-config.xml file, and Struts with struts-config.xml. In each case, the DTD or schema defines the elements and tags, which are valid for the specific domain, be it EJB, Spring, or Struts. So, ejb-jar.xml can be considered a mini DSL for configuring EJB, spring-config.xml is a mini DSL for configuring Spring beans, and so on.

In essence, DSL is a fancy name for something that we use every day of our professional programming lives. There are not many applications that can be fully written in a single general-purpose language. As such, we are the everyday consumers of many different DSLs, each of which is specific to a particular purpose.

A typical day's work could involve working with Java code for program logic, CSS for styling a web page, JavaScript for providing some dynamic web content, and Ant, Maven, or Gradle to build the scripts that tie it all together. We are well used to consuming DSLs, but seldom consider producing new DSLs to implement our applications—which we should.

The evolution of programming languages

My own background is probably typical of many of my generation of old-school programmers. Back in 1986, I was a young software engineer fresh out of college. During my school and college years, I studied many different programming languages. I was fortunate in high school to have had a visionary Math teacher who taught us to program in BASIC, so I cut my teeth programming as early as 1974. Through various college courses, I came to know about Pascal, C, Fortran, Lisp, Assembler, and COBOL.

My school, college, and early professional career all reinforced a belief that programming languages were for the exclusive use of us programmers. We liked nothing better than spending hours locked away in dark rooms writing reams of arcane and impenetrable code. The more arcane and impenetrable the better! The hacker spirit prevailed, and annual competitions such as the International Obfuscated C Code Contest (IOCCC) were born.

Note

The IOCCC runs to this day. The point of the contest is to write valid but impenetrable C code that works. Check out http://www.ioccc.org to see how not to write code.

General-purpose languages

All of the teaching in college in those days revolved around the general-purpose languages. I recall sitting in class and being taught about the "two" types of programming language: machine language, and high-level languages. Both were types of general-purpose languages, in which you could build any type of application, but each language had its own strengths and weaknesses. The notion of a DSL was not yet considered as part of the teaching program. Nor was the idea that anyone other than a cadre of trained professional programmers (hackers) would ever write programs for computers. These days, the word "hacker" has bad connotations of being synonymous with virus writers and the likes. In those days, a good "hack" was an elegant programming solution to a hard problem and being called a hacker by one's peers was a badge of pride for most programmers.

The high-level programming language you used defined what type of an application programmer you were. COBOL was for business application programming, Fortran was for scientific programmers, and C was for hackers building Unix and PC software. Although COBOL and Fortran were designed to be used in a particular business domain, they were still considered general-purpose languages. You could still write a scientific application in COBOL or a business application in Fortran if you wanted to. However, you were unlikely to try any low-level device driver development in COBOL.

Although it was possible to build entire applications in assembly language (and many people did), high-level languages, such as C, BASIC, and COBOL, were much better suited to this task. The first version of the world-beating spreadsheet Lotus 1-2-3 was written entirely in 8086 assembly language, and ironically, it was the rewrite of this into the supposed high-level language C that nearly broke the company in the late 1980's.

Languages such as C and C++ provide the low-level functionality in a high-level language, which enabled them to be used across a much greater range of domains, including those where assembly was utilized before. These days, Java, C# and C++ compete with each other like the Swiss Army knives of general-purpose languages. There are almost no application domains to which these languages have not been applied, from space exploration, through to enterprise business systems, and mobile phones.

Spreadsheets and 4GLs

Programs such as Lotus 1-2-3 and its precursor VisiCalc revolutionized people's view of who would program computers. A whole generation of accountants, financial analysts, scientists, and engineers came to realize that they can develop sophisticated turnkey solutions for themselves, armed only with a spreadsheet and a little knowledge of macros. Spreadsheet macros are probably one of the first DSLs to find their way out of the cloisters of the IT community and into the hands of the general business user.

Around this time, there was also much media attention paid to the new 4GL (fourth-generation language) systems. 4GLs were touted as being hugely more efficient for developing applications than traditional high-level languages, which then became known as third-generation language (3GL). From the hype in the media at the time, you would be forgiven for thinking that the age of the professional programmer was coming to an end and that an ordinary business user could use a 4GL to develop their own business applications. I viewed this claim with a degree of healthy skepticism—how could a non-programmer build software?

Like DSLs, 4GLs were, generally speaking, targeted at particular problem spaces, and tended to excel at providing solutions in those narrow target markets. The sophistication of most applications in those days was such that it was possible to build them with a few obvious constructs. 4GLs tended to be turnkey environments with integrated tools and runtime environments. You were restricted by the environment that the 4GL provided, but the applications that could be built with a 4GL could be built rapidly, and with a minimal amount of coding.

4GLs differ from our modern understanding of a DSL. We generally think of a DSL as being a mini language with a particular purpose, and they do not generally impose an entire runtime or tool set on their use. The best DSLs can be mixed and matched together, and used in conjunction with a general-purpose programming language, such as C++ or Java, to build our applications.

Language-oriented programming

Martin Fowler has spoken about the use of many mini DSLs in application development. He advocates building applications out of many mini DSLs, which are specific to the particular problem space, in a style of development called language-oriented programming. In a way, this style of programming is the norm for most developers these days, when we mix and match HTML, CSS, SQL, and Java together to build our applications.

The thrust of language-oriented programming is that we should all be going beyond exploiting these generally available languages and implementing our own DSLs that represent the particular problem space that we are working on. With a language-oriented programming approach, we should be building DSLs that are as narrowly focused as the single application that we are currently working on. A DSL does not need to be generally applicable to be useful to us.

Who are DSLs for?

It's worth considering for a moment who the different types of users of a DSL might be. Most DSLs require some programming skills in order to get to grips with them, and are used by software and IT professionals in their daily chores, building, and maintaining and managing systems. They are specific to a particular technical aspect of system development. So the domain of CSS as a DSL is web development in general, and specifically page styling and layout. Many web developers start from a graphic design background and become proficient as coders of HTML, CSS, and JavaScript simply because it gives them better fine-grained control of the design process.

Many graphic designers, for this reason, eventually find themselves eschewing graphical tools such as Dreamweaver in favor of code. Hopefully, our goal in life will not be to turn everybody into a coder. Whereas most DSLs will remain in the realm of the programmer, there are many cases where a well-designed DSL can be used by other stakeholders in the development process other than professional developers. In some cases, DSLs can enable stakeholders to originate parts of the system by enabling them to write the code themselves. In other cases, the DSL can become a shared representation of the system. If the purpose of a particular DSL is to implement business rules then, ideally, that DSL should express the business rule in such a way that it can be clearly understood upon reading by both the business stakeholder who specified it and the programmer who wrote it.

A DSL for process engineers

My own introduction to the concept of DSLs came about in 1986 when I joined Computer Products Inc. (CPI) as a software engineer. In this case, the DSL in question was sophisticated enough to enable the stakeholders to develop large parts of a running system.

CPI developed a process control system, which was primarily sold to chemical and pharmaceutical industries. It was a genuinely distributed system when most process control systems were based on centralized mini or mainframe computers. It had its own real-time kernel, graphics, and a multitude of device drivers for all types of control and measurement devices. But the most innovative part of the system, which excited customers, was a scripting language called EXTended Operations Language (EXTOL). EXTOL was a DSL in the purest sense because it drew the domain experts right into the development process, as originators of the running code.

With EXTOL, a chemical process engineer or chemist could write simple scripts to define the logic for controlling their plant. Each control block and measurement block in the system was addressable from EXTOL. Using EXTOL, a process engineer could write control logic in the same pseudo English that they used to describe the logic to their peers.

The following script could be deployed on a reactor vessel to control the act of half-filling the vessel with the reactant from VALVE001:

drive VALVE001 to OPEN
when LEVELSENSOR.level >= 50%
drive VALVE001 to CLOSED

This was an incredibly powerful concept. Up to this point, most process control systems were programmed in a combination of high-level languages on the main process system, and relay logic on PLCs in the plant. Both tasks required specific programming skills, and could not generally be completed by the chemists or chemical engineers, who designed the high-level chemical processing undertaken at the plant. I recall a room full of white-coated chemists at one plant happily writing EXTOL scripts, as we commissioned the plant.

The proof of the pudding is always in the eating, and I don't recall a CPI engineer ever being called upon to write a single line of EXTOL code on behalf of a customer. Given an appropriate DSL that fit their needs, our customers could write all of the code that they need themselves, without having to be programmers.

This shows the power of DSLs at their best. At this extreme end of the spectrum, a DSL becomes a programming tool that a domain expert can use independently, and without recourse to the professional programmer. It's important to remember, however, that the domain experts in this case were mostly process engineers. Process engineers are already well accustomed to devising stepwise instructions, and building process flows. They will often use the same visual representations as a programmer, such as a flow chart to express a process that they are working on.

When devising a DSL for a particular domain, we should always consider the stakeholders who need to be involved in using it. In the case of EXTOL, the DSL was targeted at a technical audience who could take the DSL and become part of the system development process. Not all of our stakeholders will be quite as technical as this. But, at the very least, the goal when designing a DSL should be to make the DSL understandable to nontechnical stakeholders.

Stakeholder participation

It's an unfortunate fact that with many DSLs, especially those based on XML, the code that represents a particular domain problem is often only legible to the programming staff. This leads to a disconnect between what the business analysts and domain experts define, and what eventually gets implemented in the system. For instance, a business rule is most likely to be described in plain English by a business analyst in a functional specification document. But these rules will most likely be translated by developers into an XML representation that is specific to the particular rules engine, which is then deployed as a part of the application. If the business analyst can't read the XML representation and understand it, then the original intent of the rule can easily be lost in translation.

With language-oriented programming, we should aim to build DSLs that can be read and understood by all stakeholders. As such, these DSLs should become the shared living specification of the system, even if in the end they must, by necessity, be written by a programmer with a technical understanding of the DSL.

DSL design and implementation

DSLs can take many different forms. Some DSLs, such as Unix mini languages, (sed, awk, and troff) have a syntactical structure, which is unique to that particular language. To implement such DSLs, we need to be able to parse this syntax out of the text files that contain the source code of that particular language. To implement our own DSL in this style involves implementing a mini compiler that uses lexing and parsing tools such as lex, yacc, or antlr.

Compiler writing is one particular skill that is outside the skill set of most application development teams. Writing your own parser or compiler grammar is a significant amount of effort to go to, unless the DSL is going to be used generally, and is beyond the scope of most application-specific DSLs.

EXTOL circumvented this problem by having its own syntax-sensitive editor. Users edited their EXTOL scripts from within the editor, and were prompted for the language constructs that they needed to use for each circumstance. This ensured that the scripts were always well-formed and syntactically correct. This also meant that the editor can save the scripts in an intermediate p-code form so that the scripts never existed as text-based program files, and therefore never needed to be compiled.

Many of the DSLs that we use are embedded within other languages. The multitude of XML configuration scripts in the Java platform are an example of this. These mini DSLs piggyback on the XML syntax, and can optionally use an XML DTD or schema definition to define their own particular syntax. These XML-based DSLs can be easily validated for "well-formedness" by using the DTD or schema.

External versus internal DSLs

We generally refer to DSLs that are implemented with their own unique syntax as external DSLs, and those that are implemented within the syntax of a host language as embedded or internal DSLs. Ideally, whenever building a new DSL, it would be best to give it its own unique and individual syntax. By designing our own unique syntax, we can provide language constructs, which are designed with both the problem domain and the target audience in mind.

If the intended user of the DSL is a non-programmer, then developing an XML-based syntax can be problematic. XML has its own particular rules about opening, closing, and properly terminating tags that appear arcane to anybody except a programmer. This is a natural constraint when working with DSLs that are embedded/internal to another language. An XML-based DSL cannot help being similar to XML.

Embedded/internal DSLs will never be as free-form as a custom external DSL due to the constraints of the host language. Fortunately, Groovy-based DSLs are capable of being structured in a more human-readable format. However, they always need to use well-formed Groovy syntax, and there are always going to be compromises when designing Groovy-based DSLs that are readable by your target audience.

Operator overloading

Some general-purpose languages, such as C++, Lisp, and now Groovy, have language features that assist in the development of mini language syntaxes. C++ was one of the earliest languages to implement the concept of operator overloading. By using operator overloading, we can make non-numeric objects behave like numeric values by implementing the appropriate operators. So, we can add a plus operator to a String object in order to support concatenation. When we implement a class that represents a numeric type, we can add the numeric operators again to make them behave like numeric primitives. We can implement a ComplexNumber class, which represents complex numbers, as follows:

class ComplexNumber {
public:
double real, imag;
        ComplexNumber() { real = imag = 0; }
        ComplexNumber(double r, double i) { real = r; imag = i; }
        ComplexNumber& operator+(const ComplexNumber& num);
};

To add one complex number to another, we need to correctly add each of the real and imaginary parts together to generate the result. We implement an equality operator for ComplexNumber as follows:

ComplexNumber& ComplexNumber::operator=(const ComplexNumber& num) {
       real = num.real;
       imag = num.imag;
       return *this;
}

This allows us then to add ComplexNumber objects together as if they were simple numeric values:

int main(int argc, const char* argv[]) {
      ComplexNumber a(1, 2), b(3, 4);
      ComplexNumber sum;
      sum = a + b;
      cout << "sum is " << sum.real << " ; "
           << sum.imaginary << "i" << endl;
}

One of the criticisms of the operator overload feature in C++ is that when using operator overloading, there is no way to control what functionality is being implemented in the overloaded function. It is perfectly possible—but not very sensible—to make the + operator subtract values and the operator add values. Misused operator overloading has the effect of obfuscating the code rather than simplifying it. However, sometimes this very obfuscation can be used to good effect.

The preceding example illustrates what could be considered as a classic case of obfuscation in C++. If your use of C++ predated the introduction of the standard C++ libraries and the streams libraries in particular, you will probably do a double take when looking at this code.

The example uses what has become commonly known as the stream operator <<. This operator can be used to send a character stream to standard output, the logic being that it looks very much like how we stream output from one program to another in a Unix shell script. In fact, there really is no such thing as a stream operator in C++ and what has been overloaded here is the binary left shift operator <<. I have to admit that my first encounter with a code like this left me perplexed. Why would anybody want to left shift the address of a string into another object was beyond me? Common use over the intervening years means that this is now a perfectly natural coding style for all C++ programmers. In effect, the streaming operator implements a mini internal DSL for representing streaming. It subverts the original language a little by using an operator out of context, but the end effect is perfectly understandable and makes sense.

During a fireside chat event at JavaOne some years ago, James Gosling was asked if he would ever consider operator overloading for the Java language, and the answer was a resolute no! Fortunately, we don't have to wait and see if Oracle will ever add operator overloading to Java. With Groovy, we can have it now. Groovy has an extensive set of features, including operator overloading that allow us to implement feature-rich DSLs from within the language. We'll take a look at some of those features that distinguish it from Java, now.

Groovy

In the later chapters of this book, we will discuss the Groovy language in detail, but let's begin with a brief introduction to the language and some of the features that make it a useful addition to the Java platform.

The Java platform has expanded over the years to cover almost all conceivable application niches—from Enterprise applications, to mobile and embedded applications. The core strengths of Java are its rich set of APIs across all of these problem domains and its standardized virtual machine (VM) interface. The standard VM interface has meant that the promise of "write once, run anywhere" has become a reality. The JVM has been implemented on every hardware architecture and operating system from the mightiest mainframe down to the humble Lego Mindstorms robotic kits for kids.

On top of this standard VM, the list of APIs that have been built extends into every conceivable domain. In addition to the standard APIs that are a part of JME, JSE, and JEE, which are extensive in themselves, there are literally thousands of open source component libraries and tools to choose from. All of this makes for a compelling argument for using Java for almost any software project that you can think of.

For many years of its evolution, the JVM was considered to be just that—a virtual machine for running Java programs. The JVM spec was designed originally by James Gosling to be used exclusively for the Java language. In recent years, there have been a number of open source projects that have started to introduce new languages on top of the JVM, such as JRuby (an implementation of the Ruby language), Jython (an implementation of the Python language and Groovy), Clojure, and Scala.

A natural fit with the JVM

Groovy differs from the preceding languages, as the Groovy language was designed specifically to be a new language to run on the JVM. Groovy is designed to be source compatible with the Java language as well as being binary-compatible at the byte code level.

James Strachan and Bob McWhirter started the Groovy project in August 2003 with the goal of providing a new dynamic and object-oriented language, which can run on the JVM. It took several existing dynamic languages, such as Ruby, Python, Dylan, and Smalltalk, as its inspiration. James had looked at the Python scripting language and had been impressed with the power that it had over Java. James and Bob wanted to design a language that had the powerful scripting features of Python, but stayed as close to the Java language as possible in terms of its syntax.

Groovy is code compatible with Java, and for this reason, it is possible in most cases to take an existing .java file and rename it to .groovy and it will continue to work. Groovy has its own compiler, groovyc, which generates Java byte code from Groovy source files just as the javac compiler does. Groovyc generates class files, which run directly on the JVM. Methods defined in a Groovy class can be called directly from Java and vice versa.

Groovy classes and interfaces are 100 percent binary compatible with their Java counterparts. Uniquely, this means that we can create a new Groovy class that extends a Java class or implements a Java interface. You can also create Java classes that extend Groovy classes or implement Groovy interfaces.

Groovy language features

Groovy adds a number of unique features that distinguish it from Java and allow developers to code at a higher level, and use a more abstract idiom, than is possible with Java. Placing all of these powerful features on top of a language that is code and API compatible with the Java platform is a powerful proposition.

Static and optional typing

In Java, as in other statically-typed languages, variables must first be declared with a type before they can have a value assigned to them. In Groovy, type can be left to be determined at the time of assignment. Groovy supports both static and optional typing as follows:

String str1 = "I'm a String"
def str2 = "I'm also a String"

Both variables str1 and str2 are of the type String. The late binding of the type in the Groovy-style assignment allows for a much less verbose code.

Native support for lists and maps

One of the great bugbears of the Java language is the cumbersome interfaces required for list and map manipulation. Groovy adds native support for all of the Java collection types through a very intuitive and readable syntax. The following code:

def authors =  [ 'Shakespeare', 'Beckett', 'Joyce', 'Poe' ]
println authors
println authors[2]

Produces this output:

[Shakespeare, Beckett, Joyce, Poe]
Joyce

Maps are also declared with ease:

def book = [ fileUnder: "Software Development",
         title: "Groovy for DSL" , author: "Fergal Dearle"]
println book
println book['title']
println book.title

This produces the following output:

[fileUnder: Software Development, title: Groovy for DSL, author: Fergal Dearle]
Groovy for DSL
Groovy for DSL

Closures

Closures are one of the most powerful language features in Groovy. Closures are anonymous code fragments that can be assigned to a variable. Closures can be invoked by the call method as follows:

def biggest = { number1, number2 ->
  number1<number2?number2:number1 
}
// We can invoke the call method of  the Closure class
def result = biggest.call(7, 1)
println result
// We can use the closure reference as if it were a method
result = biggest(3, 5)
println result
// And with optional parenthesis
result = biggest 13, 1
println result

Closures can contain multiple statements and can therefore be as complex as you like. In the following example, we iterate through a list looking for the biggest number, and return it when we are done:

def listBiggest = { list ->
    def biggest = list[0]
    for( i in list) 
        if( i > biggest) 
            biggest = i    
    return biggest
}
def numberList = [ 8, 6, 7, 5, 3, 9]
println listBiggest( numberList) 

Groovy operator overloading

Operator overloading is a powerful feature of the C++ language. Java inherited many of the features of the C++ language, but operator overloading was significantly left out. Groovy introduces operator overloading as a base language feature.

Any Groovy class can implement a full set of operators by implementing the appropriate corresponding method in the class. For example, the plus operator is implemented via the plus() method.

Regular expression support

Groovy builds regular expression handling right into the language via the =~ operator and matcher objects. The following example creates a regular expression to match all multiple occurrences of the space character. This creates a matcher object from this expression and applies it to a string by using the replaceAll method:

def lorem = 
"Lorem ipsum dolor sit amet, consectetur adipisicing elit"
println lorem
def matcher = lorem =~ " +"
def removed = matcher.replaceAll(" ")
println removed

Optional syntax

Optional typing means that variable type annotations are optional. This does not mean that variables have an unknown variable type. It means that the type will be determined at run time based on the value that gets assigned to the variable. All of the following are legal syntax in Groovy:

int a = 3 
def b = 2
String t = "hello" 
def s = 'there'

Trailing semicolons at the end of statements are optional. The only time that you explicitly need to use a semicolon in Groovy is to separate statements that occur on the same line of code, as shown in the first and third lines in the following code:

int a = 3; int b = 4;
def c = 2 
def d = 5; def e = 6

Method call parentheses are also optional when the method being invoked has passed some parameters. We saw earlier, with closures, that we can invoke a closure through its reference as if it were a method call. When invoking a closure in this way, we can also drop the parentheses when passing parameters, as shown in the following code:

println( a );
c = 2
print c
printit = { println it }
printit c

These make for a much looser programming style, which is closer to the scripting syntax of Ruby or Python. This is a big benefit when we are using Groovy to build DSLs. When our target audience is nontechnical, being able to drop parentheses and semicolons will make our code much more legible. Consider the following example, where we have two methods, or closures, to get an account by ID and then credit the account with some funds:

Account account = getAccountById( 234 );
creditAccount( account, 100.00 );

With optional types, such as parentheses and semicolons, this can be used to write code that is far more legible to our target audience:

account = getAccountById 234
creditAccount account, 100.00

Groovy markup

There are a number of builder classes built in Groovy. There are markup builders for HTML, XML, Ant build scripts, and for Swing GUI building. Markup builders allow us to write code to build a tree-based structure directly within our Groovy code. Unlike API-based approaches for building structures, the tree-like structure of the resulting output is immediately obvious from the structure of our Groovy markup code. Consider the following XML structure:

<?xml version="1.0"?>
<book>
   <author>Fergal Dearle</author>
   <title>Groovy for DSL</title>
</book>

In Groovy markup, this XML can be generated simply with the following code fragment:

def builder = new groovy.xml.MarkupBuilder()
builder.book {
   author 'Fergal Dearle'
   title 'Groovy for DSL'
}

At first glance, this looks like strange special case syntax for markup. It's not! The structure of this code can be explained through the use of closures and the optional syntax that we've discussed in this chapter. We will go into this in great detail in Chapter 5, Groovy Closures, but it is interesting at this point to see how the clever use of some language features can yield a powerful DSL-like markup syntax.

Breaking down the preceding code a little, we can rewrite it as:

def builder = new groovy.xml.MarkupBuilder()
def closure = {
   author 'Fergal Dearle'
   title 'Groovy for DSL'
}
// pass a closure to book method
builder.book( closure)
// which can be written without parentheses
builder.book closure
// or just inline the closure as a parameter
builder.book {
…
}

In other words, the code between the curly braces is in fact a closure, which is passed to the book method of MarkupBuilder. Parentheses being optional, we can simply declare the closure inline after the method name, which gives the neat effect of seeming to mirror the markup structure that we expect in the output.

Similarly, author and title are just method invocations on MarkupBuilder with the optional parentheses missing. Extending this paradigm a little further, we can decide to have author take a closure parameter as well:

def builder = new groovy.xml.MarkupBuilder()
builder.book {
   author {
                first_name 'Fergal'
                surname 'Dearle'
         }
   title 'Groovy for DSL'
}

This will output the following nested XML structure:

<?xml version="1.0"?>
<book>
   <author>
              <first_name>Fergal</first_name>
              <surname> Dearle</surname>
   </author>
   <title>Groovy for DSL</title>
</book>

Tip

Downloading the example code

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

The method calls on MarkupBuilder start off by outputting an opening XML tag, after which they invoke the closure if one has been passed. Finally, the XML tag is properly terminated before the method exits. If we analyze what happens in sequence, we can see that book invokes a closure that contains a call to author. Additionally, the author tag contains a closure with calls to first_name, surname, and so on.

Before you go to the Groovy documentation for MarkupBuilder to look for the book, author, and surname methods in MarkupBuilder, let me save you the effort. They don't exist. These are what we call pretend methods. We will see later in the book how Groovy's metaprogramming features allow us to invoke methods on closure that don't really exist, but have them do something useful anyway.

Already, we are seeing how some of the features of the Groovy language can coalesce to allow the structuring of a very useful DSL. I use the term DSL here for Groovy builders because that is essentially what they are. What initially looks like special language syntax for markup is revealed as being regular closures with a little bit of clever metaprogramming. The result is an embedded or internal DSL for generating markup.

Summary

So, now we have a feel for DSLs and Groovy. We have seen how DSLs can be used in place of general-purpose languages to represent different parts of a system. We have also seen how adding DSLs to our applications can open up the development process to other stakeholders in the development process. We've also seen how, in extreme cases, the stakeholders themselves can even become co-developers of the system by using DSLs that let them represent their domain expertise in code.

We've seen how using a DSL that makes sense to a nontechnical audience means it can become a shared resource between programming staff and business stakeholders, representing parts of the system in a language that they all understand. So, we are beginning to understand the importance of usability when designing a DSL.

We have dipped a tentative toe in the water by looking at some Groovy code. We've gained an appreciation of how Groovy is a natural fit with the Java language due to its binary and class level compatibility. We have touched on the features of the Groovy language that make it unique from Java, and looked at how these unique features can be used as a basis for building on the base Groovy language with internal DSLs.

In the next chapter, we will go into more depth with the language itself and see how we can use these features to build programs. In subsequent chapters, we will dive deeper and see how the language can be exploited as an ideal platform for building DSLs on top of the Java platform.

Left arrow icon Right arrow icon

Description

The times when developing on the JVM meant you were a Java programmer have long passed. The JVM is now firmly established as a polyglot development environment with many projects opting for alternative development languages to Java such as Groovy, Scala, Clojure, and JRuby. In this pantheon of development languages, Groovy stands out for its excellent DSL enabling features which allows it to be manipulated to produce mini languages that are tailored to a project’s needs. A comprehensive tutorial on designing and developing mini Groovy based Domain Specific Languages, this book will guide you through the development of several mini DSLs that will help you gain all the skills needed to develop your own Groovy based DSLs with confidence and ease. Starting with the bare basics, this book will focus on how Groovy can be used to construct domain specific mini languages, and will go through the more complex meta-programming features of Groovy, including using the Abstract Syntax Tree (AST). Practical examples are used throughout this book to de-mystify these seemingly complex language features and to show how they can be used to create simple and elegant DSLs. Packed with examples, including several fully worked DSLs, this book will serve as a springboard for developing your own DSLs.

Who is this book for?

This book is for Java software developers who have an interest in building domain scripting into their Java applications. No knowledge of Groovy is required, although it will be helpful. This book does not teach Groovy, but quickly introduces the basic ideas of Groovy. An experienced Java developer should have no problems with these and move quickly on to the more involved aspects of creating DSLs with Groovy. No experience of creating a DSL is required.

What you will learn

  • Familiarize yourself with Groovy scripting and work with Groovy closures
  • Use the metaprogramming features in Groovy to build mini languages
  • Employ Groovy markup and builders to simplify application development
  • Familiarize yourself with Groovy markup and build your own Groovy builders
  • Build effective DSLs with operator overloading, command chains, builders, and a host of other Groovy language features
  • Integrate Groovy with your Java and JVM based applications
Estimated delivery fee Deliver to Thailand

Standard delivery 10 - 13 business days

$8.95

Premium delivery 5 - 8 business days

$45.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Sep 28, 2015
Length: 386 pages
Edition : 1st
Language : English
ISBN-13 : 9781849695404
Category :
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Thailand

Standard delivery 10 - 13 business days

$8.95

Premium delivery 5 - 8 business days

$45.95
(Includes tracking information)

Product Details

Publication date : Sep 28, 2015
Length: 386 pages
Edition : 1st
Language : English
ISBN-13 : 9781849695404
Category :
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 158.97
Groovy 2 Cookbook
$54.99
Mastering Gradle
$48.99
Groovy for Domain-Specific Languages, Second Edition
$54.99
Total $ 158.97 Stars icon

Table of Contents

13 Chapters
1. Introduction to DSLs and Groovy Chevron down icon Chevron up icon
2. Groovy Quick Start Chevron down icon Chevron up icon
3. Essential Groovy DSLs Chevron down icon Chevron up icon
4. The Groovy Language Chevron down icon Chevron up icon
5. Groovy Closures Chevron down icon Chevron up icon
6. Example DSL – GeeTwitter Chevron down icon Chevron up icon
7. Power Groovy DSL Features Chevron down icon Chevron up icon
8. AST Transformations Chevron down icon Chevron up icon
9. Existing Groovy DSLs Chevron down icon Chevron up icon
10. Building a Builder Chevron down icon Chevron up icon
11. Implementing a Rules DSL Chevron down icon Chevron up icon
12. Integrating It All Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Full star icon Half star icon 4.7
(3 Ratings)
5 star 66.7%
4 star 33.3%
3 star 0%
2 star 0%
1 star 0%
Gary B. Price Feb 24, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
This book is a gem. Though not exhaustive, it covers many Groovy DSL topics with a care and a thoughtfulness that I wish was more common. Perhaps that is because the author has experience teaching young coders. Whatever the reason, as questions occurred to me, I found them almost always subsequently answered in the text. I'm not a Groovy novice, having used it for more than a year, but several times I found succinct explanations or useful tidbits that I had wondered about but never been motivated to follow up in the day-to-day work environment. In the area of DSLs specifically, the explanations of topics like Spock and Grails in a compact, approachable form were very useful to me. The author has an obvious fondness for his topic and this helps reader motivation. It seemed to me that he was speaking from the experience of having used the things he was writing about. I read this book through my company's Safari subscription.
Amazon Verified review Amazon
George Adamopoulos May 19, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I owned an electronic edition of the first edition of the book. I liked it so much even though it was dealing with Groovy 1.x that I purchased the second edition that works with 2.x
Amazon Verified review Amazon
Sidharth Masaldaan Dec 07, 2015
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
All in all, a good introduction to DSLs in the Groovy languageThe first chapter is a decent enough introduction, it serves well to setup the rest of the book. It's a nice introduction to the concepts of DSL & explains why Groovy was chosen as the language of choice.The second chapter introduces Groovy at a basic level, one change from the previous edition that I'm happy was done, was to split the language concepts in depth into a standalone chapter. In the previous edition, the 2nd chapter was a bit of a behemoth.The third chapter introduces some basic Groovy DSL that you may or may not have heard of. This gives a nice peek into Gradle & Spock & helped me correlate how they are, in fact, DSLs.The fourth & fifth chapter introduce, in this order, Groovy's concepts (you may skip this if you aren't a total beginner with Groovy), and Closures in Groovy (you could skip this as well, unless you come from a background where closures are new, in that case, don't skip it!)It's important to note that this book isn't to learn Groovy, (I'd recommend Groovy in Action, 2nd ed from Manning), the basics that you'd need are covered, but no more, and more concepts are introduced as you need them in your DSL. I'm judging it as a gateway to DSLs in Groovy & not as a gateway to Groovy the language. Your mileage may vary, of course.Chapter 6 is where we dive into our first Groovy DSL, a Twitter client. I'm a little conflicted by the example, which is well done, but I'd personally have chosen something like a Banking example, where you could showcase different domain rules & you'd have a lot of scenarios with tons of boilerplate code in Java, which could be broken down into a Groovy DSL.Chapters 7 introduce us to some patterns & advanced techniques (or Power Features, as suggested by the chapters title) that we can leverage in our DSLs. This is where I started to sort of disagree with the book. I would have preferred that a single Domain be used as the basis for our example application/DSL, wherein we build it up & make it more feature-rich, by adding the concepts into that single DSL as these concepts are introduced to us.Don't get me wrong, the examples are clear & do a great job of explaining the concept, e.g. Chapter 10, Building a Builder, has a great example of using these patterns to build a database seed builder (something I've tried to do in Java, only to have it devolve into an unholy mess)Chapter 8 again does a good job of explaining (what is a tough topic to digest for me) Abstract Syntax Trees (ASTs), I thought it was a neat, well-thought out chapter, with a nice enough example implementation of a state machine at the end.Chapter 9 shows how Groovy DSLs Spock & Grails implement features & techniques we saw earlier, this is where the book starts to win my attention back. It was nice to see how the techniques we read about earlier are used in real-world, full-fledged DSLsChapter 11 & 12 are where it really shines again, first with an example in 11 for a rules based DSL (which should have been our example application from the beginning, in my view) & then with a full-fledged game app, complete with a backing MongoDB & a web based front-end. Again, the examples are well done, the explanation is really great.Conclusion: If you have the first edition, you could give the 2nd ed a skip. A good book, but the constant switching of contexts lost me from time-to-time. If you're looking to understand how DSLs are implemented (& want to move beyond Java) this is a nice starting point.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela