Skip to main content

From 0 to First Hit with Grails Support

Posted by manning_pubs on October 25, 2012 at 6:52 AM PDT



From 0 to First Hit with Grails Support

by Glen Smith and Peter Ledbrook, authors of Grails in Action, Second Edition

Grails is a next-generation Java web development framework that generates great developer productivity gains through the confluence of a dynamic language, a Convention over Configuration philosophy, powerfully pragmatic supporting tools, and an agile perspective drawn from the best emerging web development paradigms. This article, based on chapter 3 of Grails in Action, Second Edition, explore Grails' support for the data model portion of your applications. Click here for 43% savings on Grails in Action, Second Edition, and other related titles.

We'll explore the basics of how Grails persists domain model classes to your datastore of choice (be it a relational database or some shiny new NoSQL store) using GORM—the Grails object relational mapping implementation.

But we're practitioners, not theorists, so we'll discuss these topics while building the heart of a sample application we use throughout our book: Hubbub. We won't be spending much time on the user interface (UI) in this article, but the concepts we'll cover are fundamental for building the rock-solid data models that back our applications.

Without further ado, let's look at our sample application.

Hubbub: starting our example application

The example we're using is Hubbub, a simple micro-blogging application in the style of Twitter. You might think of it as a system that lets you send short posts about what you're hacking on right now. Friends can follow your posts to see what you're geeking out on and get motivated to check out some things for themselves. You can follow your friends' posts, too. Figure 1 shows a complete version of Hubbub in action.

Figure 1 The Hubbub we're heading towards

Tip If you haven't used Twitter yet, it's time to head on over to twitter.com and see what all the fuss is about. If you need some friends to follow, check out @glen_a_smith and @pledbrook. We have pretty geeky tweets, but we're mostly harmless.

Figure 2 The basic Hubbub data model demonstrates all the basic relationship types.

The User class holds the user's authentication details (user ID and password). But, all good social networking applications let you associate lots of bio info with each user (profile pic, email, blog, time zone, and favorite rock star, for example), so we'll model that in a Profile class (which is an optional 1:1 relationship—each User may optionally have one Profile, and each created Profile relates to one, and only one, User).

The point of Hubbub is to let users create posts—one-line blog entries that describe what they're hacking on right now. A user will write many posts, and each Post has a single author, so that is a classic 1:m relationship.

But what's a Social Networking application without hashtags? Applications like Twitter make great use of #hashtags to see what topics are “trending” or “so hot right now” amongst the users. Every time a user creates a Post, they can apply various hashtags to it—a given Post can have many tags. But that means the reverse is also true. Each Tag can also relate to many Posts. We have an m:n (many-to-many) relationship. We're also going to link the Tag back to the User object (because it would be handy to see all the tags that a user has available without searching all their posts.

We've saved the trickiest part until last: the User object has some self-references. A User can follow many other Users (which we're calling a “following” relationship). That sounds like it would be exhausting to implement, but it turns out to be straightforward.

Domain-driven design

If you're as impatient as we are, you're probably wondering why we're starting with all this domain model design stuff here. Why not something a little more sexy, like an autocompleting Ajax-powered search gizmo?

Grails is designed to be an interactive agile development framework. That means you can start anywhere you like, refactor, make changes, and still end up with a fantastic app. You can start with the UI, domain modeling, service classes, or even the test cases if you like.

When we're working on Grails apps, the first thing we usually do is scratch out some screen designs on graph paper, as shown in figure 3. This gives us a good feel for how the user will interact with the system and some sense of how the finished product might end up looking. This gets us in the headspace of the application and gives us some ideas about the user experience. Peter likes to do this kind of stuff on his iPad but I'm a little more low-tech, so I'll scratch out something like this:

Figure 3 Early screen designs for the Hubbub UI

But, when developing any kind of webapp, the UI is only part of the story. Once we have our UI sketches mocked up, we move on and define the domain model: how all of the persistent data in the system fits together. This gives us a good feel for how the core parts of the system will collaborate, and it helps us flesh out our thinking. Grails makes domain modeling so easy that we usually do this bit directly in code without any real data model on paper. Domain modeling is a great place to start your Grails application development journey.

Data modeling is where we'll stop in this article, but, after we define our data model, we use Grails to generate a quick-and-dirty scaffold UI. With our autogenerated UI, we feel like we've made some progress—we have a basic app running and persisting to a database—so we're motivated to move on to the next level of functionality in our app and start implementing our graph paper scratchings as a real UI.

We'll now get Hubbub to the point where you can see it running in a browser.

We have the rough version of our screens on paper, and we have a “napkin-level” data model to work from, so it's time to start generating our application. Let's create the app:

grails create-app hubbub

We always find it's good encouragement to do a cd hubbub followed by an initial grails run-app to start our newly created application. Point your browser at http://localhost:8080/hubbub/ to see things up and running, as shown in figure 4.

Figure 4 The newly created Hubbub application

With the shell of Hubbub created, it's time to put some meat on the bones. Before we generate our first domain class, let's take a quick look at GORM, the Grails object relational mapping implementation.

Introducing Grails object relational mapping (GORM)

Object-relational mapping (ORM) is the process of getting objects into and out of a persistent datasource (you might be using a relational database, an object database, or one of the new NoSQL databases, but Grails abstracts most of these details for you). Having an ORM layer like GORM means you can (mostly) be oblivious to the SQL/NoSQL that's happening behind the scenes and get on with the coding. For example, if you call user.firstName = "Glen", the ORM might create the SQL UPDATE statement to ensure that the object is persisted in your relational database or the JSON to send it to a NoSQL store. In Java applications, that role is usually handled by an ORM like Hibernate or JPA; in Grails, it's done by GORM, which takes full advantage of Groovy's dynamic typing to make data access simple.

If you've used Hibernate, EclipseLink, or another Java ORM library, you'll know that a lot of configuration is required. Often, there's a bunch of XML mapping files to write or annotations to add to each of your persistent classes—and there might be a ton of transactional behavior to configure up too. GORM, like most of Grails, uses Convention over Configuration to get you up and running without a single line of XML.

Now that you know a bit about GORM, it's time to define our first domain model object and see things in action.

Your first domain class object

We outlined the preliminary model at the beginning of this article, and we have our application shell in place, so it's time to define our data model classes. One of the first things we'll need to define is a User object, so that our users can sign up and start using the system.

The first step is to ask Grails to create a skeleton of our domain class for us:

grails create-domain-class com.grailsinaction.User

This creates a new class file in /grails-app/domain/com/grailsinaction/User.groovy (and a corresponding unit test in /test/unit/com/grailsinaction/UserTests.groovy). It's good practice to store classes in packages rather than in the default scope, so we'll keep all of our source in a package called com.grailsinaction.

Do I have to type the package name *every* time?

If you forget to type a package name when creating artifacts, Grails will automatically prefix the value with the name of the application. So, in the above case, if we'd just run a grails create-domain-class User, it would have ended up in a class called hubbub.User.

But, the good news is that conventions are always configurable! If you have a look in /grails-app/conf/Config.groovy, you'll find an entry titled:

grails.project.groupId = appName 

You can change this line to be your default package name and forget having to type package names ever again! For example, you might change it to:

grails.project.groupId = 'com.grailsinaction' 

We won't change the value for this article since we want you to get used to practicing package-based creation, but if you're already a package ninja, feel free to make the mod.

Now it's time to start thinking about some of the fields we'll want to define for new User accounts. We don't want the signup process to be too onerous, but we'll need at least a few basics from our users. Listing 1 introduces our first basic User object.

Listing 1 Our first basic User object

package com.grailsinaction

class User {
    String userId
    String password
    String homepage
    Date dateCreated
}

Types that can be used in domain classes

You can use an extensive range of Java types: Integer, Long, Float, Boolean (and their corresponding primitive types), Date, Calendar, URL, and byte[] are all in the list of supported types. Grails will also make sensible choices about an appropriate database type to map what you're storing. See the Hibernate documentation for a full set of supported types.

Grails provides special support for date fields named dateCreated and last-Updated. If you have fields with such names, Grails will automatically set the current timestamp value on first save to dateCreated or on every save to lastUpdated. You can use dateCreated to preserve the user's registration time.

We can now store a user's details. We don't have a UI to enter anything yet, but we do have the shell of a test case, which Grails created for us. Creating a shell test case is supposed to reduce the friction in getting you started on writing tests for your code.

New in 2.0: Massive Testing Refactor

In Grails 2.0, the whole testing infrastructure (and particularly unit testing) has had a massive overhaul. If you've been around the Grails block, you know that Unit Testing support in Grails 1.x was clunky, tedious and often incomplete, which provided a high friction for getting solid tests written for your app. This has been completely rewritten in Grails 2.0.

Summary

We discussed Grails support for building applications and using domain-driven design. You've learned how Grails Object-relational mapping (GORM) takes full advantage of Groovy's dynamic typing to make data access simple. You've also learned that you should create your basic domain model classes as the first step in your application, and use scaffolding to get them online.


Here are some other Manning titles you might be interested in:

Griffon

Griffon in Action
Andres Almiray, Danno Ferrin, and James Shingler

Groovy in Action, Second Edition

Groovy in Action, Second Edition
Dierk Koenig, Guillaume Laforge, Paul King, Jon Skeet, and Hamlet D'Arcy

Spring in Action, Third Edition

Spring in Action, Third Edition
Craig Walls


AttachmentSize
grails001.gif18.36 KB
grails002.gif5.53 KB
grails003.gif17.89 KB
grails004.png56.85 KB
grails006.jpg24.95 KB
grails005.jpg9.11 KB
grails007.jpg24.72 KB