-1

I use a Grails Job to start a Service which uses g.formatDate. When using the service directly from a Controller I have no problem. When I use the Service from the Job I get the following error:

ERROR listeners.ExceptionPrinterJobListener  - Exception occurred in job: Grails Job
Message: java.lang.NullPointerException
   Line | Method
->> 111 | execute in grails.plugins.quartz.GrailsJobFactory$GrailsJob
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|   202 | run     in org.quartz.core.JobRunShell
^   573 | run . . in org.quartz.simpl.SimpleThreadPool$WorkerThread
Caused by NullPointerException: null
->> 245 | $tt__sendReportCompanyWeekly in Test.SendMailService$$EPPc274K
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|    47 | doCall  in Test.ReportCompanyWeeklyJob$_execute_closure1
|    31 | execute in Test.ReportCompanyWeeklyJob$$EPPc2HTU
|   104 | execute in grails.plugins.quartz.GrailsJobFactory$GrailsJob
|   202 | run . . in org.quartz.core.JobRunShell
^   573 | run     in org.quartz.simpl.SimpleThreadPool$WorkerThread

Here is my Job:

class ReportCompanyWeeklyJob {  

  SendMailService sendMailService


  static triggers = {
    cron name: 'scheduledReportCompanyWeeklyJob', cronExpression: "0 15 22 ? * *" 
  }

  def execute() {
    sendMailService.sendReportCompanyWeekly(company.id, user.id)
  }

}

Here is my Service:

@Transactional
class SendMailService {

    def gspTagLibraryLookup  // being automatically injected by spring
    def g

  def sendReportCompanyWeekly(String companyId, String userId) {    
    g = gspTagLibraryLookup.lookupNamespaceDispatcher("g")

    Date today = new Date()
    Locale locale = // some locale

    // Line 245
    def test = g.formatDate(date: today, formatName: 'date.format.long.no.year', locale: locale)  

 }

}

Edit: I use groovyPageRenderer.render(template: viewPathHTML, model: myModel) to render a GSP in a service.

How can I make g.formatDate work when running from a Job?

Michael
  • 32,527
  • 49
  • 210
  • 370

1 Answers1

2

grails.gsp.PageRenderer is limited in what it can render because it doesn't have the same context as rendering GSP pages from a controller.

When using a formatName, g.formatDate() attempts to get a Locale from the the GrailsWebRequest. The Locale is used to retrieve 'date.format.long.no.year' from a MessageSource. The problem is grails.gsp.PageRenderer does not have a GrailsWebRequest. You can see the g.formatDate() source code here.

Work-around

You can work around this problem by formatting the date in the service and passing it to the GSP via the model. Something like this:

import java.text.SimpleDateFormat

@Transactional
class SendMailService {

    ...
    def messageSource // Injected to look up 'date.format.long.no.year'

    def sendReportCompanyWeekly(String companyId, String userId) {    
        Date today = new Date()
        Locale locale = // some locale

        def formattedDate = new SimpleDateFormat(messageSource.getMessage('date.format.long.no.year', null, locale), locale)
            .format(today)

        /* 
          1. Add the formattedDate to the PageRenderer model, 
          2. Update the GSP code to use the value from the model instead of g.formatDate()
        */
    }

}

Better idea - create a formatDate Closure

import java.text.SimpleDateFormat

@Transactional
class SendMailService {

    ...
    def messageSource // Injected to look up 'date.format.long.no.year'

    def sendReportCompanyWeekly(String companyId, String userId) {    
        Date today = new Date()
        Locale locale = // some locale

        def formatter= new SimpleDateFormat(messageSource.getMessage('date.format.long.no.year', null, locale), locale)

        def formatDate = { Date date -> formatter.format(date) }

        /* 
          1. Add the formatDate Closure to the PageRenderer model, 
          2. Update the GSP code to use the Closure from the model instead of g.formatDate()
        */
    }

}
Emmanuel Rosa
  • 9,697
  • 2
  • 14
  • 20