Annotating Your Grails Controller Classes And Actions
2011-02-25 10:04:37 | 4 Comments
For the current project of mine which I'm building with Grails I needed to annotate my controller classes and some actions in some cases. I had no idea on how to do it but I think I have just solved it and I am sharing it with you and I think I will stop saying that I am not a Java person as Groovy and Grails stuff is pushing me into both Java and its ecosystem.
The best example for explaining this would be security. Imagine you have a controller class that you don't want your regular members to access so you add `@RequireRole("Admin")` above your controller class. Whenever a member tries to access that annotated controller class they will be redirected to an unauthorized page unless they are admin.
CREATING THE ANNOTATION
----------
For the beginning, lets create our annotation:
//src/java/your/package/RequireRole.java
package net.mengu.grails.sample;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface RequireRole {
String value();
}
What we should draw your attention here is that `ElementType.TYPE` makes the annotation available to classes and `ElementType.FIELD` makes the annotation available to controller actions.
ANNOTATING THE CONTROLLER CLASS
----------
Now that we have created our annotation, we can annotate our controller class.
package net.mengu.grails.sample
@RequireRole("Admin")
class SiteController {
def index = {
}
}
HOW TO CHECK THE CLASS ANNOTATION
----------
We are going good. Now the question pops up here. How do we check if user has the required role? In my opinion, Grails filters are a gift for this operation. We can create a filter in our `/grails-app/conf` directory named `SecurityFilters.groovy`. How do we find the controller class? Great question! We have grailsApplication exposed to us which also has controllerClasses property that we can use. We also know the name of the controller via `controllerName` property in our filter so let's act!
//grails-app/conf/SecurityFilters.groovy
import net.mengu.grails.sample.RequireRole
class SecurityFilters {
def filters = {
loginCheck(controller:'*', action:'*') {
before = {
def controllerClass = grailsApplication.controllerClasses.find { it.fullName.indexOf(controllerName.capitalize()+"Controller") != -1 }
def classAnnotated = controllerClass.getClazz().isAnnotationPresent(RequireRole)
if (classAnnotated) {
def requiredRole = controllerClass.getClazz().getAnnotation(RequireRole).value()
if (session.user?.role != requiredRole) {
redirect(uri:"/unauthorized")
}
}
}
}
}
}
Let me explain what's going on over there in a minute. We are using before filter for every controller and every action. In our filter, we get the controller class as an object as we already have its name, we just get it from `grailsApplication.controllerClasses`. After that, we check if the class has the annotation and if it has the annotation present we get its value and we do our check.
HOW TO CHECK THE ACTION ANNOTATION
----------
We are done with controlling the class annotation. How do we check the action annotation? It was a little bit tricky for me to do so as I am not a Grails Master yet. We have the controller class object already so what we need to do is getting the list of action objects. Action objects of a controller class can be accessed with `controllerClass.getClazz().declaredFields` so let's make an addition to `SecurityFilters.groovy` file.
//grails-app/conf/SecurityFilters.groovy
import net.mengu.grails.sample.RequireRole
class SecurityFilters {
def filters = {
loginCheck(controller:'*', action:'*') {
before = {
def controllerClass = grailsApplication.controllerClasses.find { it.fullName.indexOf(controllerName.capitalize()+"Controller") != -1 }
def classAnnotated = controllerClass.getClazz().isAnnotationPresent(RequireRole)
if (classAnnotated) {
def requiredRole = controllerClass.getClazz().getAnnotation(RequireRole).value()
if (session.user?.role != requiredRole) {
redirect(uri:"/unauthorized")
}
}
if (actionName) {
def controllerAction = controllerClass.getClazz().declaredFields.find { it.toString().indexOf(actionName) != -1 }
def actionAnnotated = controllerAction.isAnnotationPresent(RequireRole)
if (actionAnnotated) {
def actionRequiredRole = controllerAction.getAnnotation(RequireRole).value()
if (session.user?.role != actionRequiredRole) {
redirect(uri:"/unauthorized")
}
}
}
}
}
}
}
That is all now. We have an annotation, we have annotated class and we have a mechanism processing what we need if the annotation is present. Hope you guys enjoyed the tutorial!
Did you enjoy this post? You should follow me on twitter here.


Comments
Leave a Response