InfoQ

News

Article: An Approach to Internal Domain-Specific Languages in Java

Posted by Ryan Slobojan on Feb 19, 2008 12:00 PM

Community
Java
Topics
Domain Specific Languages
Tags
Language Features,
Patterns,
Language Oriented Programming,
Languages

In this article, Alex Ruiz and Jeff Bay describe Java's suitability as a DSL-producing language, delve into the creation of internal DSLs in Java, walk through an example of a Java-based internal DSL, and give recommendations on writing DSLs in Java.

From the article's conclusion:

Java can be suited to create internal domain-specific languages that developers can find very intuitive to read and write, and still be quite readable by business users. DSLs created in Java may be more verbose than the ones created with dynamic languages. On the bright side, by using Java we can exploit the compiler to enforce semantics of a DSL. In addition we can count on mature and powerful Java IDEs that can make creation, usage and maintenance of DSLs a lot easier.

Creating DSLs in Java also requires more work from API designers. There is more code and more documentation to create and maintain. The results can be rewarding though. Users of our APIs will see improvements in their code bases. Their code will be more compact and easier to maintain, which can simplify their lives.

There are many different ways to create DSLs in Java, depending on what we are trying to accomplish. Although there is no "one size fits all" approach, we have found that combining method chaining and static factory methods and imports can lead to a clean, compact API that is both easy to write and read.

Read the full article here.

14 comments

Reply

Brilliant article by Henri Frilund Posted Feb 19, 2008 12:39 PM
A Pointless Exercise by Erkki Lindpere Posted Feb 19, 2008 1:09 PM
Re: A Pointless Exercise by Michael Hunger Posted Feb 20, 2008 12:24 AM
Very good read. by Richard L. Burton III Posted Feb 19, 2008 1:37 PM
Good stuff by Manuel Palacio Posted Feb 19, 2008 4:16 PM
Re: SQL-Example by Michael Hunger Posted Feb 19, 2008 5:10 PM
Additional resources by Michael Hunger Posted Feb 19, 2008 5:30 PM
Re: Additional resources by Michael Hunger Posted Feb 19, 2008 5:47 PM
Very Beneficial by Jacob Northey Posted Feb 19, 2008 9:13 PM
Re: Very Beneficial by Michael Hunger Posted Feb 20, 2008 12:13 AM
Re: Very Beneficial by Jacob Northey Posted Feb 20, 2008 7:40 AM
Very nice (but is it a DSL?) by Ron Kersic Posted Feb 20, 2008 2:30 AM
A Great Article by John DeHope Posted Feb 20, 2008 10:42 AM
Another nice example of an internal DSL for integration by David Greco Posted Feb 26, 2008 7:07 AM
  1. Back to top

    Brilliant article

    Feb 19, 2008 12:39 PM by Henri Frilund

    Very interesting article. I'm right now working on a personal project trying to create a tool for creating web applications with an internal Java-hosted DSL, backed by a component model (Wheel). Designing the API is indeed quite difficult especially if the DSL is rather large. Worst problems for me so far have been limitations posed by the static type system (which on the other hand helps a lot when using the DSL with a modern IDE), method grouping and not having named attributes. Thanks to some of the ideas in your article, I think I can get around the missing named attributes. The grouping-issue...by which I mean the situation where you start to have dozens of methods (DSL expressions) in a class and you need some way to group them functionally, but can't break the class-hierarchy either (in my case the DSL is used by extending a a class containing the DSL so I can't split the class itself). I ended up creating sort of "side-show" classes that hold the methods, but share state with the "main" class. Example: A Configuration-class that holds method for manipulating the "main" classes configuration properties. The "main" class then as a method that returns the Configuration-object. In code it looks like this:

    config().
        initialFieldValue("guess", "give a number").
        exposeField("guess");
    
    What the config() does is that is returns the Configuration-object with methods that will return this. It's not very OO, but it works and the result looks pleasing. Not sure if the grouping-issue is common, but thought I'd mention it. -Henri

  2. Back to top

    A Pointless Exercise

    Feb 19, 2008 1:09 PM by Erkki Lindpere

    Creating internal DSL-s in Java is a pointless exercise. Scala, Groovy, JRuby or another DSL-friendly language should be used instead. My personal preference is Scala. It has limitations on how nice the syntax can be, but it performs as well as Java, unlike the dynamically typed languages.

  3. Back to top

    Very good read.

    Feb 19, 2008 1:37 PM by Richard L. Burton III

    I know a lot of developers are often reluctant to follow a DSL naming convention like expressed in the examples contained within this article. I've recently become a firm believer in method chaining and following what I like to call "DSL Naming Convention". Good job guys. Best Regards, Richard L. Burton III

  4. Back to top

    Good stuff

    Feb 19, 2008 4:16 PM by Manuel Palacio

    Very good article. Looking forward to seeing more of the SQL example.

  5. Back to top

    Re: SQL-Example

    Feb 19, 2008 5:10 PM by Michael Hunger

    Perhaps you'd like to have a look at the embedded Java-SQL DSL named JEQUEL. See http://www.jequel.de.If someone is interested to join we also have a codehaus project at http://jequel.codehaus.org. Small example:

    public void testSimpleSql() {
            final SqlString sql =
                    select(ARTICLE.OID)
                            .from(ARTICLE, ARTICLE_COLOR)
                            .where(ARTICLE.OID.eq(ARTICLE_COLOR.ARTICLE_OID)
                                    .and(ARTICLE.ARTICLE_NO.is_not(NULL)));
    
            assertEquals("select ARTICLE.OID" +
                         " from ARTICLE, ARTICLE_COLOR" +
                         " where ARTICLE.OID = ARTICLE_COLOR.ARTICLE_OID" +
                         " and ARTICLE.ARTICLE_NO is not NULL", sql.toString());
        }
    
    For some more material on DSLs have a look at the DSL-Book (Work in Progress) and the thoughtworks podcast by Martin Fowler. Have fun Michael

  6. Back to top

    Additional resources

    Feb 19, 2008 5:30 PM by Michael Hunger

    Nat Pryce and Steve Freeman did a lot of this java dsl stuff during the jMock and Hamcrest development. Martin Fowler links to the paper regarding jmock at the end of the expression builder bliki entry. The blog of Nat Pryce is an invaluable source regarding java DSLs in the domain of testing (i.e. jmock, test data builders, etc.) There is an ongoing effort of the Quaere Team led by Anders Norås to build a LINQ like DSL for java. Michael

  7. Back to top

    Re: Additional resources

    Feb 19, 2008 5:47 PM by Michael Hunger

    Sorry, I forgot: Guice binding setup is also an internal DSL in java. The DSL booking example is totally confusing. You have inconsistent syntax mixed with imperative methods (add) and I doubt that a user of such an DSL would know which methods to call on which objects and which Parameter objects to fill in created by the (he has to know this) statically imported methods. There is also a missing paren at the last line (in both boxes). Something more interesting would be:

    Trip trip = 
    on("10/09/2007").flyWith(airline("united").flight("UA-6886"))
    .to(city("Paris").hotel("Hilton"))
    .andReturnWith(airline("united").flight("UA-6887")).on("10/17/2007")
    
    What I also miss is the discussion of the concrete usage of interfaces as intermediary builder objects. This is much more important as it is java's only way to support multiple inheritance (and you need this when composing grammars from reusable expressions). See Martins Book for details. Michael

  8. Back to top

    Very Beneficial

    Feb 19, 2008 9:13 PM by Jacob Northey

    Great article, I'm sure we will see some if not all of this content in an upcoming DSL book. Although I would never use an internal DSL in Java as a customer facing DSL, using the builder pattern and method chaining is extremely beneficial for generating test objects in unit tests. It is much more communicative than a simple ObjectMother which hides a lot of the test values inside static factory methods. Somebody should create a code generation library for generating builders from POJOs. That would reduce a lot of time spent keeping builder code current with the POJOs.

  9. Back to top

    Re: Very Beneficial

    Feb 20, 2008 12:13 AM by Michael Hunger

    The book by Martin Fowler is as cited already in progress. Nat Pryce did quite a lot with the TestDataBuilders you mention. I agree that an internal DSL in a language like Java is nothing for customers (neither reading nor writing) although reading may be improved by changing the color scheme of the IDE to fade parentheses, semicolons, brackets, language identifiers as suggested by Nat Pryce, Anders Noras and others. (see http://nat.truemesh.com/archives/000188.html) The generic pojo builder generation thing would only work if you could specify the relevant attributes that shall be a part of the language and also define the associations between your POJOs. Choosing the right names for the fluent interfaces (which often don't correspond to the names of the attributes set but are more natural language constructs) is another problem with a generic approach. Michael

  10. Back to top

    Re: A Pointless Exercise

    Feb 20, 2008 12:24 AM by Michael Hunger

    I don't agree with you. Please don't forget that there is not only the top notch of the developer crowd you see here at infoq, the other online resources and the conferences. If I look around my workplace there is a lot of people who just do java and have neither heard nor used Scala, Ruby, Groovy and the like. So a DSL in Java is a first step to take in this direction when introducing DSLs and fluent interfaces in an development team/organisation. The static typing helps a lot when someone learns a new DSL (if you are fluent in your DSL a dynamic language should pose no problem but I don't want to imagine having a customer staring at the error messages of the ruby or groovy runtime due to misspelled syntax). So editor support is quite important here. You could argue that a tool like the xText facilities of openArchitectureWare (http://openarchitectureware.org/) would be a better choice their with their full fledged text editor generation support. But they don't generate DSLs for executable languages per se but parsers for creating/reading models. Michael

  11. Back to top

    Very nice (but is it a DSL?)

    Feb 20, 2008 2:30 AM by Ron Kersic

    Nice article! But I’d argue that it is more on fluent interfaces then on (internal) DSL’s. I know the issue of is-it-a-DSL-or-not is a bit of a grey area but my personal litmus test is on the errors and warnings thrown at me when creating a program with the DSL. I expect a DSL to be supported by errors and warnings at the level of the DSL and not at the level of the language implementing the DSL. In case of the of the booking example, I’d guess that if I type booking.add(airline(“united”)) the error would be that the booking.add method expects a BookableItem (instead of an Airline). But for a ‘real’ DSL I want the error message to state that I need to specify a flight to go with that airline. Likewise, if I’d type booking.add(flight(“UA-6868”)) I want a warning message stating that this flight is interpreted to be by United Airlines and I want to be offered a quick fix to add the airline(“united”) bit. I guess it comes down to the fact that you need to have some processing on top of what the IDE does on processing Java in order to get at a internal DSL in Java. The Spoon framework (http://spoon.gforge.inria.fr/) is a relatively easy way of getting such processing in place. I’m building an internal DSL with Spoon (http://funkydsl.wiki.sourceforge.net/, no code yet alas) and from what I know, the errors and warnings for the booking example above would be very easy to implement with Spoon. Most certainly worth checking out. \Ron

  12. Back to top

    Re: Very Beneficial

    Feb 20, 2008 7:40 AM by Jacob Northey

    Thanks for pointing out Nat's blog. The entry http://nat.truemesh.com/archives/000728.html is exactly what I was looking for in terms of using TestDataBuilders instead of an ObjectMother. As for the generic pojo builder generation, I would be willing to give up a little readability for a lot less effort. This is especially the case for large generated domain models on small projects where the effort required to maintain TestDataBuilders is not warranted. The main goal I'm looking for in TestDataBuilders is conciseness.

    public class Car {
        private Color color;
        private Model model;
        private Manufacturer manufacturer;
        // Getters and Setters
        ...
    }
    
    Car car = car().color(RED).manufacturer(manufacturer("Ford")).model(model("Fusion")).build();
    
    The above code, similar to the article's dreamCar code, can be generated straight from POJOs where the static builderfactory methods manufacturer and model reflect required constructor parameters. Another approach I like is using variable length argument lists with named parameters instead of chaining with() calls:
    Car redFusion = car(color("red"), manufacturer("Ford"), model("Fusion"));
    Car blueIon = car(year(2005), color("blue"), manufacturer("Saturn"), model("Ion"));
    

  13. Back to top

    A Great Article

    Feb 20, 2008 10:42 AM by John DeHope

    A fantastic article. I really enjoyed the discussion about how to actually build a fluent API. You see a lot of blog articles about what they are, and what they look like. This was the first article I read that explained some of the thought process that goes into actually building them up from scratch. Nice!

  14. Camel defines an internal DSL based on the enterprise integration patterns. Using this nice DSL it's possible to easily define messaging routes among different endpoints. http://activemq.apache.org/camel/

Exclusive Content

Agile Project Management: Lessons Learned at Google

In this presentation filmed during QCon 2007, Jeff Sutherland, the creator of Scrum, talks about his visit at Google to do an analysis of Google's first implementation of Scrum.

AtomServer – The Power of Publishing for Data Distribution

In this article, Bryon Jacob and Chris Berry introduce AtomServer, their implementation of a full-fledged Atom Store based on Apache Abdera, which is now available as open source.

An Introduction to Virtualization

It is easy to think that virtualization applies only to servers. In reality the recent resurgence of the concept is also being applied to networking, storage, and application infrastructure.

REST Anti-Patterns

In this article, Stefan Tilkov explains some of the most common anti-patterns found in applications that claim to follow a "RESTful" design and suggests ways to avoid them.

Choosing between Routing and Orchestration in an ESB

In this article, Adrien Louis and Marc Dutoo discuss the differences and relative merits of using orchestration vs. routing in a typical ESB setup, and discuss various implementation options.

Enterprise Batch Processing with Spring

Wayne Lund discusses batch processing, Spring Batch objectives and features, scenarios for usage, Spring Batch architecture, scaling, example code, failures and retrying, and the future roadmap.

User Story Estimation Techniques

Developer Jay Fields draws on his experiences as a ThoughtWorks consultant to describe effective user story estimation techniques.

Security (CAS and OpenID) with Ruby

In this talk from QCon SF 2007, Justin Gehtland explains two open solutions to distributed identity and their Rails integration components: OpenID (using ruby-openid) and CAS (using rubycas-client).