Skip to content

rendering outside of web requests not working anymore #60

Description

@zyro23

Expected Behavior

rendering should work within and outside the context of web requests (as it used to).

Actual Behaviour

rendering now only works within the context of web requests.

outside of web requests (e.g. async tasks, quartz jobs, etc.), a NullPointerException is thrown:

java.lang.NullPointerException: Cannot invoke "org.grails.web.servlet.mvc.GrailsWebRequest.getOut()" because the return value of "org.grails.web.taglib.encoder.WebOutputContextLookup$WebOutputContext.lookupWebRequest()" is null

i guess this change is relevant: 364bd4e
RenderEnvironment.init() is now only applied for Environment.TEST, which was not the case before.

trying to reproduce this, i saw that the code in question is using GrailsWebMockUtil which in turn uses spring-test classes (e.g. MockHttpServletRequest).
Those now seem not to be present on the runtime classpath anymore but on the test classpath only (which by itself is an improvement).
However this results in missing RequestAttributes/GrailsWebRequest with the error above outside of web requests.

perhaps worth a thought would be to use PageRenderer which takes care of (re-)setting the RequestAttributes/GrailsWebRequest instead of using GroovyPagesTemplateEngine directly?

Steps To Reproduce

  • run sample app
    • see stacktrace
java.lang.NullPointerException: Cannot invoke "org.grails.web.servlet.mvc.GrailsWebRequest.getOut()" because the return value of "org.grails.web.taglib.encoder.WebOutputContextLookup$WebOutputContext.lookupWebRequest()" is null
	at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
	at java_util_concurrent_Future$get.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:130)
	at com.example.BootStrap$_closure1.doCall(BootStrap.groovy:12)
	at com.example.BootStrap$_closure1.doCall(BootStrap.groovy)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:280)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1009)
	at groovy.lang.Closure.call(Closure.java:433)
	at groovy.lang.Closure.call(Closure.java:412)
	at grails.util.Environment.evaluateEnvironmentSpecificBlock(Environment.groovy:572)
	at grails.util.Environment.executeForEnvironment(Environment.groovy:565)
	at grails.util.Environment.executeForCurrentEnvironment(Environment.groovy:541)
	at org.grails.web.servlet.boostrap.DefaultGrailsBootstrapClass.callInit(DefaultGrailsBootstrapClass.java:71)
	at org.grails.web.servlet.context.GrailsConfigUtils.executeGrailsBootstraps(GrailsConfigUtils.java:88)
	at org.grails.plugins.web.servlet.context.BootStrapClassRunner.onStartup(BootStrapClassRunner.groovy:59)
	at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy:317)
	at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:455)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:388)
	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:1013)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:631)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)
	at grails.boot.GrailsApp.run(GrailsApp.groovy:111)
	at grails.boot.GrailsApp.run(GrailsApp.groovy:428)
	at grails.boot.GrailsApp.run(GrailsApp.groovy:417)
	at com.example.Application.main(Application.groovy:11)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50)
Caused by: java.lang.NullPointerException: Cannot invoke "org.grails.web.servlet.mvc.GrailsWebRequest.getOut()" because the return value of "org.grails.web.taglib.encoder.WebOutputContextLookup$WebOutputContext.lookupWebRequest()" is null
	at org.grails.web.taglib.encoder.WebOutputContextLookup$WebOutputContext.getCurrentWriter(WebOutputContextLookup.java:87)
	at org.grails.taglib.encoder.OutputEncodingStack.lookupCurrentWriter(OutputEncodingStack.java:122)
	at org.grails.taglib.encoder.OutputEncodingStack.createNew(OutputEncodingStack.java:94)
	at org.grails.taglib.encoder.OutputEncodingStack.currentStack(OutputEncodingStack.java:86)
	at org.grails.taglib.encoder.OutputEncodingStack.currentStack(OutputEncodingStack.java:73)
	at org.grails.taglib.encoder.OutputEncodingStack.currentStack(OutputEncodingStack.java:63)
	at org.grails.taglib.encoder.OutputEncodingStack.currentStack(OutputEncodingStack.java:57)
	at org.grails.taglib.encoder.OutputEncodingStack.currentStack(OutputEncodingStack.java:49)
	at grails.artefact.TagLibrary$Trait$Helper.getOut(TagLibrary.groovy:114)
	at org.grails.plugins.web.taglib.GrailsLayoutTagLib.getOut(GrailsLayoutTagLib.groovy)
	at org.grails.plugins.web.taglib.GrailsLayoutTagLib$_closure1.doCall(GrailsLayoutTagLib.groovy:130)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:280)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1009)
	at groovy.lang.Closure.call(Closure.java:433)
	at org.grails.gsp.GroovyPage.invokeTagLibClosure(GroovyPage.java:469)
	at org.grails.gsp.GroovyPage.invokeTag(GroovyPage.java:387)
	at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
	at sample_demo_grails_app_views__example_gsp.run(sample_demo_grails_app_views__example_gsp:16)
	at org.grails.gsp.GroovyPageWritable.doWriteTo(GroovyPageWritable.java:151)
	at org.grails.gsp.GroovyPageWritable.writeTo(GroovyPageWritable.java:89)
	at grails.plugins.rendering.document.XhtmlDocumentService$_generateXhtml_closure1.doCall(XhtmlDocumentService.groovy:70)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:280)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1009)
	at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
	at grails.plugins.rendering.document.RenderEnvironment.with(RenderEnvironment.groovy:76)
	at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
	at grails.plugins.rendering.document.RenderEnvironment.with(RenderEnvironment.groovy:66)
	at grails.plugins.rendering.document.XhtmlDocumentService.generateXhtml(XhtmlDocumentService.groovy:69)
	at grails.plugins.rendering.document.XhtmlDocumentService.createDocument(XhtmlDocumentService.groovy:39)
	at grails.plugins.rendering.RenderingService.render(RenderingService.groovy:39)
	at grails.plugins.rendering.RenderingService.render(RenderingService.groovy:38)
	at grails.plugins.rendering.RenderingService$render.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:139)
	at com.example.BootStrap$_closure1$_closure3.doCall(BootStrap.groovy:13)
	at com.example.BootStrap$_closure1$_closure3.doCall(BootStrap.groovy)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:280)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1009)
	at groovy.lang.Closure.call(Closure.java:433)
	at groovy.lang.Closure.call(Closure.java:412)
	at groovy.lang.Closure.run(Closure.java:505)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)

Environment Information

  • grails-7.2.3
  • ubuntu-24.04
  • jdk-25

Example Application

https://github.com/zyro23/grails-rendering-60

Version

7.0.1

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions