0
votes

Basically, I want to be able to assign objects created within filters to members in a base controller from which every controller extends. Any possible way to do that?

Here's how I tried, but haven't got to make it work.

What I'm trying to achieve is to have all my controllers extend a base controller. The base controller's constructor would be used to assign values to its members, those values being pulled from the session map. Example below.

File grails-app/controllers/HomeController.groovy:

class HomeController extends BaseController {
    def index = {
        render username
    }
}

File grails-app/controllers/BaseController.groovy:

abstract class BaseController {
    public String username

    public BaseController() {
        username = session.username
    }
}

When running the app, the output shown is:

2010-06-15 18:17:16,671 [main] ERROR [localhost].[/webapp]  - Exception sending context initialized event to listener instance of class org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pluginManager' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.RuntimeException: Unable to locate constructor with Class parameter for class org.codehaus.groovy.grails.commons.DefaultGrailsControllerClass
    ...
Caused by: java.lang.RuntimeException: Unable to locate constructor with Class parameter for class org.codehaus.groovy.grails.commons.DefaultGrailsControllerClass
    ...
Caused by: java.lang.reflect.InvocationTargetException
    ...
Caused by: org.codehaus.groovy.grails.exceptions.NewInstanceCreationException: Could not create a new instance of class [com.my.package.controller.HomeController]!
    ...
Caused by: groovy.lang.MissingPropertyException: No such property: session for class: com.my.package.controller.HomeController
    at com.my.package.controller.BaseController.<init>(BaseController.groovy:16)
    at com.my.package.controller.HomeController.<init>(HomeController.groovy)
    ...
2010-06-15 18:17:16,687 [main] ERROR core.StandardContext  - Error listenerStart
2010-06-15 18:17:16,687 [main] ERROR core.StandardContext  - Context [/webapp] startup failed due to previous errors

And the app won't run.

This is just an example as in my case I wouldn't want to assign a username to a string value, but rather a few objects pulled from the session map. The objects pulled from the session map are being set within filters.

The alternative I see is being able to access the controller's instance within the filter's execution. Is that possible?

Please help! Thanks a bunch!

3

3 Answers

4
votes

You typically can't do much in the constructor in Grails artifacts. You can use an interceptor for this though:

abstract class BaseController {
   protected String username

   def beforeInterceptor = {
      username = session.username
   }
}

This is described in section 6.1.5 of http://grails.org/doc/latest/

0
votes

You can use a request scoped service...

0
votes

As a rule, I'd caution against putting state directly in a controller; controllers in general (regardless of framework) are generally intended to be stateless. I'd stick with the standard webapp state constructs like request and session to store and transfer data.

For your specific case, I'd do one of the following:

  • If lightweight data (primitives), I'd store them in the session and just access them as needed:
    e.g. render session.username

  • If dynamic or database-driven data, I'd create a service and pull the data as needed: e.g. homeService.getUser().username

  • As a variation to your discussion with Burt above, you could use a filter to populate a request or session value as well.