0

I am in the process of upgrading to Grails 4.0.1 and I'm having problems with internationalization. I keep getting a NullPointerException error java.lang.NullPointerException: Cannot invoke method getMessage() on null object. The line of code causing the error is:

  return messageSource.getMessage('dashboard.completed.label', 'Approved', LocaleContextHolder.getLocale())

When I println(messageSource), the value is null. I have tried adding

   spring: 
       messages:
           basename: grails-app/i8n/** 

to my application.yml, but I still get the same error. I thought maybe the problem is that a bean is missing from my resources.groovy, so I added the following messageSource bean to resources.groovy:

   beans = {
        messageSource(ReloadableResourceBundleMessageSource){
            basename = grails-app/i18n/messages
        }
   }

However, this produces the following error org.grails.core.exceptions.GrailsConfigurationException: Error loading spring/resources.groovy file: No such property: grails for class: grails.spring.BeanBuilder.

I then decided to try to place the bean in a resources.xml file instead of resources.groovy.

  <bean id="messageSource"
     class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
     <property name="basename" value="grails-app/i18n/" />
     <property name="defaultEncoding" value="UTF-8" />
 </bean>

But that too produces a NullPointerException. After scouring the internet, I found a resource that suggested a workaround by initializing messageSource inside bootstrap.groovy so I added the following to it:

  def messageSource

  def init = { servletContext ->
       messageSource.basenames = ['/grails-app/i18n/messages']
       messageSource.afterPropertiesSet()
  } 

That produces the same NullPointerException error.

This was working fine before I upgraded. If I println(messageSource) from inside the bootstrap.groovy, the program prints the array of basenames. However, doing println(messageSource) in my controller after injecting message source prints "null". Perhaps there is something that I missed in the upgrade process, but I am not sure what it is. Does anyone have any idea as to why I am getting the error and possible steps I could take to fix it?

  • `basename = "grails-app/i18n/messages"` – cfrick Jan 14 '20 at 15:33
  • @cfrick I had also tried that file path and I still get the `NullPointerException`. Every place where I have used `grails-app/i18n/` I have tried `grails-app/i18n/messages` and `grails-app/i18n/messages**` and I have tried enclosing the file path in quotes and without quotes and I still get the error. – No Longer Rooky Coder Jan 14 '20 at 16:16
  • Did you find a solution for this? I’m struggling with same error. For me the issue is that locally it works, without adding any bean in resources.groovy, it injects the messageSource into my service, but when I deploy on DEV env it gives me same NullPointerException... if I add the bean in resources.groovy then when I try to call messageSource.getMessage(...) it gives me an exception that it couldn’t find the key ( both locally and on DEV env) – GritcoAndreea Jan 15 '21 at 09:55
  • @GritcoAndreea I followed the example that was given in the response marked as the answer. It's working for me fine locally. I have not deployed it to my DEV env (go side tracked with client engagements) so I don't know whether an issue will arise in that environment. Sorry that I cannot offer more guidance. – No Longer Rooky Coder Jan 28 '21 at 17:20

2 Answers2

2

In controller or service import:

import org.springframework.context.MessageSource
import org.springframework.context.i18n.LocaleContextHolder

Then declare:

@Autowired
private MessageSource messageSource

And use like this:

messageSource.getMessage('my.message.properties.msg', null, 'Default Message', LocaleContextHolder.locale)

It works for me in Grails 4.0.1

Maifee Ul Asad
  • 3,992
  • 6
  • 38
  • 86
VPS
  • 21
  • 2
1

See the project at https://github.com/jeffbrown/rookiecodermessagesource.

https://github.com/jeffbrown/rookiecodermessagesource/blob/78d8760cd057b8eda25f72ddca05390463cbb68b/grails-app/init/rookiecodermessagesource/BootStrap.groovy

package rookiecodermessagesource

class BootStrap {
    def messageSource

    def init = { servletContext ->
        println messageSource
    }
    def destroy = {
    }
}

That works fine, as it should.

Jeff Scott Brown
  • 26,804
  • 2
  • 30
  • 47
  • Thank you for answering. But, I am still getting the `NullPointerException`. I can print messageSource to the console from `bootstrap.groovy`, so a messageSource is there. Injecting it into my domain and/or controller is what's failing. It is in the domain class where I am getting the `NullPointerException` `class EvaluateState { def messageSource String toString() { if (state == STATE_PROG) { return messageSource.getMessage('dashboard.inProgress.label', 'In Progress', LCH.getLocale()) } }` – No Longer Rooky Coder Jan 15 '20 at 18:59
  • "Injecting it into my domain and/or controller is what's failing" - Injecting into a domain shouldn't work because domain classes are no longer subjected to dependency injection. – Jeff Scott Brown Jan 15 '20 at 19:09
  • The commit at https://github.com/jeffbrown/rookiecodermessagesource/commit/56ba351eb7cb8b3ad704e8cca2658e5db50e1891 shows the injection working for a controller. – Jeff Scott Brown Jan 15 '20 at 19:12
  • Can I ask a followup question - this is working fine in my controller now but I am still having some issues with my domain where I also use MessageSource. If scaffolding to the domain, is it possible to also use `return messageSource.getMessage('dashboard.inProgress.label', 'In Progress', LCH.getLocale())`? Or, am I going about this the wrong way with respect to using messageSource in the domain and should really just use it in the controller? – No Longer Rooky Coder Jan 15 '20 at 22:22
  • "Or, am I going about this the wrong way with respect to using messageSource in the domain and should really just use it in the controller?" - For most cases you really shouldn't do either. I provided an example of doing in a controller in response to your comment that the DI isn't happening there. In general, strive to keep your controllers simple and focused on just web layer stuff. Much of the work that folks put in controllers is better suited being peeled out into a service that gets injected in the controller. – Jeff Scott Brown Jan 15 '20 at 22:33
  • If you fill out the consultation request form at https://objectcomputing.com/products/grails I will follow up with a call and we can discuss this. I am not trying to sell you anything, the consultation is 100% free, it is just that StackOverflow isn't great for discussing things like how best to design systems. I am happy to help and hope you will take me up on that offer. – Jeff Scott Brown Jan 15 '20 at 22:36