Customizing MOP in Groovy
July 30th, 2013
Demonstrates using the Groovy Meta Object Protocol framework to build a custom MetaClass implementation.
It is possible to embrace the misconception that Groovy is a “weakly” typed language. In actuality, Groovy is an “optionally” typed language, and that distinction is an important one to grasp when understanding the fundamentals of the language. Groovy’s nearest ancestor, Java, is said to be a “strongly” typed language, whereby the compiler knows all of the types for every variable and can understand and honor contracts at compile time. This means that method calls are able to be determined at compile time, and therefore take the onus of their resolution off of the runtime system.
When writing code in Groovy, developers are given the flexibility to provide a type or not. This can offer some simplicity in implementation and, when leveraged properly, can service your application in a robust and dynamic way. Consider the following application code were the UserController is making a call to the UserHibernateDAO to query for a user on the criteria of a first name. In this example, there is a requirement that if there are more than one User records with the provided first name, then we will display the record’s details and the record’s associated index. If there is only one record, then we can display just the record’s details, without any corresponding index.
class UserHibernateDAO {
def sessionFactory
def getByFirstName(String name) {
List<User> users = sessionFactory.createQuery("select * from user where firstName = :name")
.setParameter("name", name)
.list()
users.size() == 1 ? users[0] : users
}
}
class UserController {
UserHibernateDAO dao
def show() {
_show dao.getByFirstName(params.name)
}
private String _show(User user) {
"""\
|First Name: $user.firstName
|Middle Initial: $user.middleInitial
|Last Name: $user.lastName
|""".stripMargin()
}
private String _show(List<User> users) {
def result = []
for (int i=0;i<users.size();i++) {
User user = users[i]
result << """\
|Id: $i
|${_show(user)}
|""".stripMargin()
}
result.join()
}
}
controller.params = [name: 'Dan']
controller.show()
This code makes use of polymorphism to provide an inherent discrimination between the two business scenarios of single and multiple user records. In a traditional Java application, we would have to provide a more explicit and verbose manner of handling these two scenarios, since the compiler would demand that it know all of the types before it is able to resolve contracts within the code. In Groovy, developers are not bound by such rigidity, and as such, can make use of the fact that Groovy will resolve the object type at runtime to create a simplified implementation. The next section of code demonstrates this reality in a more simplistic context.
def build(i) {
def numbers = []
i.times { n -> numbers << n }
numbers.size() == 1 ? numbers[0] : numbers
}
String _get(Integer number) {
"single"
}
String _get(List<Integer> number) {
"multiple"
}
assert _get( build(1) ) == "single"
assert _get( build(2) ) == "multiple"
Optional typing can be a powerful utility in your development toolbelt, but if not handled responsibly, it can build complexities and obscurities in your application that may leave your code in an unmanagable state. To get a handle on how you can utilize optional typing in Groovy without getting your codebase into an unmaintainable mess, it is best to embrace the philosophy of “duck typing” in your applications.
Duck typing is a style of typing that relies heavily on the readability of your application code. As the adage goes, “if it walks like a duck and talks like a duck, then it’s probably a duck”. Following this simple principle will give you guidance when considering whether or not it is an appropriate time to employ optional typing. In most cases, it is acceptable to use optional typing with appropriately named variables and language-inherent data structures.
class User {
String firstName
String middleInitial
String lastName
}
def user = new User(firstName: "Dan", lastName: "Woods")
assert user.firstName == "Dan"
The above code shows the principle of duck typing employed with an instance of the User class. As it were, in this listing, the User object “walks like a user and talks like a user”, and therefore it must be a “user”. This code demonstrates a simple scenario where we can very easily read that the user variable was assigned to an instance of the User class, and therefore it’s not very hard for us to figure out what it is. Keeping your code segments small and isolated, where code can be easily deciphered, is an excellent architecture pattern when making use of optional typing.
When not following the principle of duck typing, even small and isolated code chunks can be made unmaintainable when employing optional typing. The example shown below demonstrates an improper use of optional typing within an application. Even though this code segment is relatively small, and the component pieces are well isolated, it’s entirely unclear what types of objects this code is working against. Given that Groovy allows you to optionally type variable arguments to methods, we could realistically pass any object to the process method and see this code fulfill its execution cycle. In a small application, it may be easy to figure out what type of object should be going through this workflow, but in any application that is beyond trivial, this code fails the test of appropriate use of optional typing.
def process(instance) {
if ( instance?.fields?.size() > 10 ) {
instance?.fields = instance?.fields[0..5]
}
instance.with {
properTypes = mediaTypes?.collect(mapTypes)
properFields = handle( fields, properTypes )
}
instance
}
def mapTypes = { t ->
t.available ? new MediaType(media: t) : new NullMediaType()
}
def handle(fields, types) {
fields.collect { f -> types?.findAll { it.media == f.name } }
}
Making use of optional typing in Groovy can garner the benefits of reduced verbosity and improved readability throughout your application’s code base. It is, however, a concept of the language that must be used responsibly. Following the principle and test of “duck typing” will service you as a guide post when determining if a scenario warrants the use of optional typing or not. It may come to be, in some cases, that in favor of a more-maintainable code-base, you need to sacrifice reduced verbosity in favor of a more clearly understood implementation. In those cases, it is perfectly acceptable to fall-back to a more Java-esque style of code authoring; indeed, not everything benefits from idiomatic Groovy. This is a point that the language developers understood well, and have decreed clearly through the insistence that Groovy enhances Java, it doesn’t replace it.
Demonstrates using the Groovy Meta Object Protocol framework to build a custom MetaClass implementation.
Describes how to use Gradle and its Shadow plugin to create a self contained, executable Jar. No more classpath management.
A tutorial with backing github project detailing how to build custom authentication solutions with the Grails Spring Security Core plugin.
Insert bio here