1

I am trying to migrate the grails-timezone-detection grails plugin to Grails 3.

In the original code there is the following method:

private def getDefaultFormTagLib() {
    return grailsApplication.mainContext.getBean('org.codehaus.groovy.grails.plugins.web.taglib.FormTagLib')
}

I rewrote it as follows:

private def getDefaultFormTagLib() {
    return grailsApplication.mainContext.getBean('org.grails.plugins.web.taglib.FormTagLib')
}

Running the test, I get the following error:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'org.grails.plugins.web.taglib.FormTagLib' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1207)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1078)
at com.captivatelabs.grails.timezone.detection.TimeZoneTagLib.getDefaultFormTagLib(TimeZoneTagLib.groovy:76)
at com.captivatelabs.grails.timezone.detection.TimeZoneTagLib$_closure3.doCall(TimeZoneTagLib.groovy:42)
at groovy.lang.Closure.call(Closure.java:414)
at org.grails.taglib.TagOutput.captureTagOutput(TagOutput.java:64)
at com.captivatelabs.grails.timezone.detection.TimeZoneTagLibSpec.test offset server to client time - datePicker(TimeZoneTagLibSpec.groovy:85)

I added the following to output the beans available to the plugin: def ctx = grailsApplication.mainContext ctx.beanDefinitionNames.sort().each { println it }

The only bean within the org.grails.plugins.web.taglib package is org.grails.plugins.web.taglib.ApplicationTagLib.

Why is the following not also available ?

  • org.grails.plugins.web.taglib.FormTagLib
  • org.grails.plugins.web.taglib.FormatTagLib

I suspect I am missing something very obvious.

Does anyone have any suggestion as to how I should proceed?

  • There is no good reason to retrieve the bean using that technique. Can you describe what it is you are going to do with the bean once you have a reference to it? – Jeff Scott Brown Feb 28 '18 at 16:00

1 Answers1

0

Strange that it doesn't work for FormTagLib because it works with ApplicationTagLib:

ApplicationTagLib g = grailsApplication.mainContext.getBean(ApplicationTagLib.class.name)

That being said, it looks like I had the same problem in one of my projects. Here's how I solved it, but obviously this isn't the best approach because dependency injection doesn't work:

private def getDefaultFormTagLib() {
    def bean = new org.grails.plugins.web.taglib.FormTagLib()
    bean.grailsTagDateHelper = new DefaultGrailsTagDateHelper()
    return bean
}

Hopefully someone else will chime in with a better answer.

doelleri
  • 19,232
  • 5
  • 61
  • 65
Dustin
  • 574
  • 6
  • 13
  • Why would you do that as opposed to letting Spring inject your tag date helper? – Jeff Scott Brown Feb 28 '18 at 16:01
  • Doing `new org.grails.plugins.web.taglib.FormTagLib()` isn't advised. That instance will not have been subjected to DI so things like the `conversionService` won't be there, the initialization stuff in `afterPropertiesSet()` won't have been run, etc. – Jeff Scott Brown Feb 28 '18 at 16:07
  • @JeffScottBrown I can't tell you the exact reason why that didn't work because this was several months ago during an upgrade to Grails 3, but I still have this in my plugin's doWithSpring()...so I know I tried that unsuccessfully: `formTagLib(FormTagLib) { grailsFormTagLib(org.grails.plugins.web.taglib.FormTagLib)}` This plugin is similar to the timezone detection plugin in that it needs to override the default FormTagLib, but still needs access to the default implementation. – Dustin Feb 28 '18 at 18:39
  • You don't have to inject the `FormTagLib` into your custom tag in order to invoke tags that are provided by `FormTagLib`. One solution is to invoke them as methods from your custom tag with no explicit reference to the `FormTagLib` class. The details depend on what you are trying to do. – Jeff Scott Brown Feb 28 '18 at 19:18
  • In my project, I'm overriding the default date picker when the precision is not time, but providing the default implementation otherwise. In timezone detection, the date picker binding converts the user's local time to server time (i.e. UTC) and then formatDate is overridden to convert the server time to the user's local time. – Dustin Feb 28 '18 at 19:31
  • Thanks for the guidance @JeffScottBrown, I have reworked the architecture somewhat and now DI is no longer needed. – Pieter Malan Mar 01 '18 at 11:00