1

In grails 4, if I had plugin-A that defined a taglib with static namespace = "someNamespace", I could reference that in controllers in plugin-B via something like:

render someNamespace.sometag()

In grails 4.0.3, plugin-B had a compile dependency on plugin-A, now it has an implementation dependency. Trying to run the same code, now gives the error:

"No such property: someNamespace for class: com.package.PluginBController"

Attempting to use the same namespace in the application that's running with both plugins A and B works just fine, but calling it from a Controller provided by plugin B fails. Are we missing something with the grails 5 upgrade? Does this need to be injected somehow?

Trebla
  • 1,164
  • 1
  • 13
  • 28
  • There is no good reason to inject a taglib into a controller. – Jeff Scott Brown Aug 02 '22 at 16:28
  • 1
    Ok... but we're already using taglibs in controllers (whether we should be or not, it's 10 year old code at this point) to prevent code duplication... is that no longer possible? It seems that rendering a taglib as the response for a controller action is perfectly reasonable – Trebla Aug 02 '22 at 17:15
  • The grails docs explicitly say you can use taglibs in controllers. Is this no longer true and the documentation is outdated? Tags within namespaces can be invoked as methods using the namespace as a prefix to the method call: `out << my.example(name:"foo")` This works from GSP, controllers or tag libraries – Trebla Aug 02 '22 at 17:19
  • "The grails docs explicitly say you can use taglibs in controllers." - You can inject any bean into a controller and taglibs are beans, but there are no good reasons to inject a tablib into a controller. If you can point me to that section I will update those docs for clarity.. Thank you for your feedack. – Jeff Scott Brown Aug 08 '22 at 13:16
  • "The grails docs explicitly say you can use taglibs in controllers." - Are those docs at https://gsp.grails.org/latest/guide/index.html, https://docs.grails.org/latest/, or somewhere else? – Jeff Scott Brown Aug 08 '22 at 17:47
  • We may be talking about different things. When you say "inject" are you talking about bean injection? The error you describe in the question isn't related to injection. I can't tell if you are asking about using injection because that technique isn't working for you, or if that technique is what you are mean by "inject". – Jeff Scott Brown Aug 08 '22 at 17:49
  • I apologize, I was using "inject" more generically and was not referring to bean injection, but use of the namespace within the controller. – Trebla Aug 09 '22 at 11:40

1 Answers1

0

Grails 5 change: how to inject taglib into Controller

You can inject a taglib using its bean name like any other bean but there is no good reason to do that. The technique you show in the question is the recommended approach. We effectively add a namespace variable to your controllers which allow you to invoke tag lib implementations as if they were methods. That approach makes more sense than injecting a taglib.

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

https://github.com/jeffbrown/treblataglib/blob/8f6d46aa2d227ddb34dfa6adfa50d03b270ddd70/app/grails-app/controllers/app/DemoController.groovy

package app

class DemoController {

    def index() {
        render someNamespace.sometag()
    }
}

https://github.com/jeffbrown/treblataglib/blob/8f6d46aa2d227ddb34dfa6adfa50d03b270ddd70/helper/grails-app/taglib/helper/HelperTagLib.groovy

package helper

class HelperTagLib {
    static namespace = 'someNamespace'
    def sometag = { attrs ->
        out << 'This came from HelperTagLib.someTagLib'
    }
}

That appears to work:

~ $ mkdir working                                      
~ $ 
~ $ cd working                                         
working $ 
working $ git clone git@github.com:jeffbrown/treblataglib.git
Cloning into 'treblataglib'...
remote: Enumerating objects: 145, done.
remote: Counting objects: 100% (145/145), done.
remote: Compressing objects: 100% (98/98), done.
remote: Total 145 (delta 23), reused 145 (delta 23), pack-reused 0
Receiving objects: 100% (145/145), 860.12 KiB | 3.41 MiB/s, done.
Resolving deltas: 100% (23/23), done.
working $ 
working $ cd treblataglib                                    
treblataglib (main)$ 
treblataglib (main)$ ./gradlew app:bootRun                              

> Task :app:bootRun
Grails application running at http://localhost:8080 in environment: development
<============-> 95% EXECUTING [26s]
> :app:bootRun

Output:

~ $ http :8080/demo
HTTP/1.1 200 
Connection: keep-alive
Content-Type: text/html;charset=utf-8
Date: Mon, 08 Aug 2022 18:05:14 GMT
Keep-Alive: timeout=60
Transfer-Encoding: chunked
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers

This came from HelperTagLib.someTagLib

EDIT:

A comment below indicates that the problem manifests when a plugin is using a namespaced taglib from another plugin. I have updated the linked project to represent that (https://github.com/jeffbrown/treblataglib/commit/53de85ef7073b8f428ccf0e785097509ed966376).

app depends on another-helper, another-helper depends on helper. helper provides a namespaced taglib. DemoController in another-helper uses that namespaced plugin.

When run the app using Gradle it seems to work. When I build the war, that seems to work as well.

Jeff Scott Brown
  • 26,804
  • 2
  • 30
  • 47
  • Correct, this is no longer working in grails 5 when used in my above scenario where one tag is defined in Plugin A and used in Plugin B. It works just fine locally within the same application, or when using the tag from Plugin A in the application. The problem comes when a controller defined in plugin B attempts to use the namespace and tag from Plugin A. Entirely possible we did something else wrong which caused this issue. Only observed it once (so far) out of 20 interdependent plugins, but it's not a pattern we use often. – Trebla Aug 09 '22 at 11:38
  • "The problem comes when a controller defined in plugin B attempts to use the namespace and tag from Plugin A."- Got it. I didn't realize that it had to be a plugin using a tag from another plugin. I have an app using a tag from a plugin. That was my mistake. I will investigate. Thank you for the feedback. We will get it fixed. – Jeff Scott Brown Aug 09 '22 at 12:40
  • @Trebla I edited the question to indicate what I have tried to do to recreate the problem and I cannot. If you would file an issue at https://github.com/grails/grails-gsp/issues and provide a sample app, we will get it straightened out. I am sorry for the trouble. Thank you for the feedback! – Jeff Scott Brown Aug 09 '22 at 12:51
  • No problem, hard to communicate clearly especially in unformatted comment blocks on SO :). I will try to get a sample app, but in the meantime we've changed the parts that were broken and moved on. Working on getting our full application upgraded, so it may be a bit before I can get to a sample app. Thanks for the insights. – Trebla Aug 09 '22 at 16:24
  • "I will try to get a sample app, but in the meantime we've changed the parts that were broken and moved on." - I am sorry that I couldn't help. Best of luck. – Jeff Scott Brown Aug 09 '22 at 17:58