This article is based on Making Java Groovyand the book will release on January 2011. It is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) ebooks and pbooks. MEAPs are sold exclusively through Manning.com. All print book purchases include an ebook free of charge. When mobile formats become available all customers will be contacted and upgraded. Visit Manning.com for more information.
also read:
- Java Tutorials
- Java EE Tutorials
- Design Patterns Tutorials
- Java File IO Tutorials
Introduction
POGOs have more capabilities than POJOs. For example, all POGOs have a map-based constructor that is very convenient for setting properties. The interesting thing is that, even if a class is written in Java, many of the same conveniences apply as long as it is accessed from Groovy. Consider a simple POJO representing a person, possibly created as part of a domain model in Java.
Listing 1 A simple POJO representing a person
public class Person { private int id; private String name; public Person() {} public Person(int id, String name) { this.id = id; this.name = name; } public void setId(int id) { this.id = id; } public int getId() { return id; } public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + "]"; } }
The Person class contains attributes representing an id and a name, which are the only really significant pieces of information in the class. The rest of the class is made up of constructors, getters, and setters, and an override of the toString method to make it easier to print instances to the console. Any typical Java persistence layer has dozens of classes just like this, which easily map to relational database tables.
The interesting thing is that, if we instantiate this class from Groovy, we can use a map-based constructor to do so, even though the Java version already specifies two constructors and neither is the one we want. Let’s create some Person instances from Groovy using three different mechanisms, none of which appear in the Java class.
Figure 1 Groovy adds a map-based constructor to Java classes, regardless of what constructors are already included
def buffy = new Person(name:'Buffy') assert buffy.id == 0 assert buffy.name == 'Buffy' def faith = new Person(name:'Faith',id:1) assert faith.id == 1 assert faith.name == 'Faith' def willow = [name:'Willow',id:2] as Person assert willow.id == 2 assert willow.name == 'Willow'
The instances buffy and faith are created using the map-based constructor, first setting only the name and then setting both the name and the id. I’m then able to verify, using Groovy’s built-in assert method (omitting its optional parentheses) that the person’s properties are set correctly.
Incidentally, all of the assert statements that seem to be accessing private properties of the class directly really aren’t. Groovy goes through the getter and setter methods provided in the Java class when it looks like properties are being accessed or assigned. We can prove this by modifying the implementation of the getter method to return more than just the name:
public String getName() { return "from getter: " + name; }
Now we have to modify each of the asserts to include the string “from getter: ” for them to still return true.
The third person, willow, is constructed using the “as” operator in Groovy. This operator has several uses, one of which is to “coerce” a map into an object, as shown here. In this case, the operator instantiates a person and supplies the map as properties for the resulting instance.
Moving on, we can also add our person instances to a Groovy collection, which isn’t all that surprising but has some nice additional benefits. For example, Groovy collections support operator overloading, making it easy to add additional persons and have additional methods for searching.
def slayers = [buffy, faith] assert ['Buffy','Faith'] == slayers*.name assert slayers.class == java.util.ArrayList def characters = slayers + willow assert ['Buffy','Faith','Willow'] == characters*.name def doubles = characters.findAll { it.name =~ /([a-z])\1/ } assert ['Buffy','Willow'] == doubles*.name
Groovy has a native syntax for collections, which simplifies Java code. Putting the references inside square brackets creates an instance of the java.util.ArrayList class and adds each element to the collection. Then,in the assert statement, I used the so-called spread-dot operator to extract the name property from each instance and return a list of the results (in other words, the spread-dot operator behaves the same way collect does). By the way, I restored the getName method to its original form, which returns just the attribute value.
I was able to use operator overloading to add willow to the slayers collection, resulting in the characters collection. Finally, I took advantage of the fact that in Groovy, the java.util.Collections interface has been augmented to have a findAll method that returns all instances in the collection matching the condition in the provided closure. In this case, the closure contains a regular expression, which matches any repeated lowercase letter.
Summary
Many existing Java applications have extensive domain models. As you can see, Groovy code can work with them directly, even treating them as POGOs and giving you a poor-man’s search capability.