You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@grails.apache.org by "jamesfredley (via GitHub)" <gi...@apache.org> on 2026/03/15 21:40:23 UTC
[I] GSP layout tags from @CompileStatic TagLib classes are not discoverable as bare method calls [grails-core]
jamesfredley opened a new issue, #15506:
URL: https://github.com/apache/grails-core/issues/15506
## Summary
Tags defined in `RenderGrailsLayoutTagLib` (e.g., `pageProperty`, `layoutTitle`, `layoutBody`) cannot be called as bare methods in GSP expression syntax (`${pageProperty(name: 'meta.description')}`). They work correctly with the explicit `g.` namespace prefix (`${g.pageProperty(name: 'meta.description')}`).
The root cause is that `RenderGrailsLayoutTagLib` has `@CompileStatic` at class level, and `DefaultGrailsTagLibClass` tag discovery does not find `Closure`-typed properties on `@CompileStatic` classes.
## Version
Grails 7.0.x (all versions since 7.0.0-M5, when `RenderGrailsLayoutTagLib` was introduced). Tested on 7.0.9-SNAPSHOT.
## Steps to Reproduce
1. Create a layout GSP (e.g., `layouts/marketing.gsp`)
2. Use `pageProperty` as a bare method call in a GSP expression:
```gsp
<meta name="description" content="${pageProperty(name: 'meta.description') ?: 'default'}"/>
```
3. Visit a page that uses this layout
**Expected:** The page renders normally, `pageProperty` resolves to the tag from `RenderGrailsLayoutTagLib`.
**Actual:** 500 error: `No signature of method: ...marketing_gsp.pageProperty() is applicable for argument types: (LinkedHashMap)`
## Workaround
Using the explicit `g.` namespace prefix works:
```gsp
<meta name="description" content="${g.pageProperty(name: 'meta.description') ?: 'default'}"/>
```
This is because `g.pageProperty()` goes through `GroovyPage.getProperty("g")` -> `NamespacedTagDispatcher` -> `TagLibraryLookup.lookupTagLibrary()`, which is a different resolution path that works correctly.
## Root Cause Analysis
### Tag discovery mechanism
`DefaultGrailsTagLibClass` (line 62-71) discovers tags by iterating metaclass properties:
```java
for (MetaProperty prop : GroovySystem.getMetaClassRegistry().getMetaClass(clazz).getProperties()) {
int modifiers = prop.getModifiers();
if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
continue;
}
if (Closure.class.isAssignableFrom(prop.getType())) {
tags.add(prop.getName());
}
}
```
When a TagLib class has `@CompileStatic`, Groovy 4 compiles the `Closure` property fields differently. The metaclass property type no longer reports as `Closure`, so `Closure.class.isAssignableFrom(prop.getType())` returns false, and the tags are not registered.
### Two resolution paths
| Call syntax | Resolution path | Works? |
|---|---|---|
| `g.pageProperty(name: ...)` | `GroovyPage.getProperty("g")` -> `NamespacedTagDispatcher.methodMissing` -> `TagLibraryLookup.lookupTagLibrary("g", "pageProperty")` | Yes |
| `pageProperty(name: ...)` | `ExpandoMetaClass.methodMissing` -> `TagLibraryMetaUtils.methodMissingForTagLib` -> `TagLibraryLookup.lookupTagLibrary("g", "pageProperty")` | No |
Both paths use the same `TagLibraryLookup`. The bare method path fails because the tag was never registered in the lookup's `tagNamespaces` map (due to the property scanning issue above). The `g.` path works because the `NamespacedTagDispatcher` has its own `methodMissing` that still finds the bean.
### Confirmed by test
Locally removed `@CompileStatic` from `RenderGrailsLayoutTagLib`, published to mavenLocal, and tested: **bare `pageProperty()` works correctly after removal**. Re-adding `@CompileStatic` breaks it again.
### Affected TagLib
`RenderGrailsLayoutTagLib` in `grails-layout` module is the only framework TagLib with class-level `@CompileStatic`. Other built-in TagLibs (e.g., `ApplicationTagLib`, `FormTagLib`, `RenderTagLib`) do not have class-level `@CompileStatic` and their tags work as bare methods.
### History
`RenderGrailsLayoutTagLib` was introduced in commit `0be9f5d486` ("revert sitemesh3 upgrade & rename sitemesh -> layout") included in 7.0.0-M5. The class-level `@CompileStatic` was present from its creation. The prior `RenderSitemeshTagLib` (Sitemesh 3, since reverted) did not have `@CompileStatic`.
## Affected tags
All tags in `RenderGrailsLayoutTagLib`:
- `pageProperty`
- `ifPageProperty`
- `layoutTitle`
- `layoutHead`
- `layoutBody`
- `applyLayout`
- `content`
## Note on documentation
The [official pageProperty docs](https://grails.apache.org/docs/7.0.0/ref/Tags%20-%20GSP/pageProperty.html) show `${pageProperty(name:'body.onload')}` without the `g.` prefix, which does not work due to this bug.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [I] GSP layout tags from @CompileStatic TagLib classes are not discoverable as bare method calls [grails-core]
Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty closed issue #15506: GSP layout tags from @CompileStatic TagLib classes are not discoverable as bare method calls
URL: https://github.com/apache/grails-core/issues/15506
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org