I am using Grails 6 to generate an API service. Im...
# questions
c
I am using Grails 6 to generate an API service. Im running into an issue when I use views to expose data. I am using Controllers that extend from RestfulController, I have simple Domain objects with limited properties and a couple of relationships. The issue arises when I have Domain classes that use CamelCase such as ClinicalCenter or MolecularMarker. Using names such as Patient is no problem. Taking the latter case; I would have a folder called patient and therein a file called _patient.gson to show the data, works as expected. Taking the first example, I would have a view folder called molecularMarker and therin a file called _molecularMarker.gson, with almost the same data as patient but I keep getting the error below. I have tried other names, such as ClinicalCenter, and all give a similar error. If I were just to use Clinic then that does work. Am I missing something that I should be configuring/setting/naming? Here is an example of the template with the error below: model { MolecularMarker marker } json { id marker.id description marker.name } 2025-07-11 105433.970 ERROR --- [nio-8080-exec-1] .a.c.c.C.[.[.[.[grailsDispatcherServlet] : Servlet.service() for servlet [grailsDispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is grails.views.ViewRenderException: Error rendering view: Error rendering view: Cannot get property 'id' on null object] with root cause java.lang.NullPointerException: Cannot get property 'id' on null object at org.codehaus.groovy.runtime.NullObject.getProperty(NullObject.java:89) at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:190) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:336) at oncode_api_molecularMarker__molecularMarker_gson$_run_closure1.doCall(oncode_api_molecularMarker__molecularMarker_gson:8) at oncode_api_molecularMarker__molecularMarker_gson$_run_closure1.call(oncode_api_molecularMarker__molecularMarker_gson) at grails.plugin.json.builder.StreamingJsonBuilder$StreamingJsonDelegate.cloneDelegateAndGetContent(StreamingJsonBuilder.java:836) at grails.plugin.json.builder.StreamingJsonBuilder.call(StreamingJsonBuilder.java:255) at grails.plugin.json.view.JsonViewWritableScript.json(JsonViewWritableScript.groovy:81) at oncode_api_molecularMarker__molecularMarker_gson.run(oncode_api_molecularMarker__molecularMarker_gson:7) at grails.plugin.json.view.JsonViewWritableScript.doWrite(JsonViewWritableScript.groovy:29) at grails.views.AbstractWritableScript.writeTo(AbstractWritableScript.groovy:40) at grails.plugin.json.view.api.internal.DefaultGrailsJsonViewHelper$5.writeTo(DefaultGrailsJsonViewHelper.groovy:763) at grails.plugin.json.view.api.internal.DefaultGrailsJsonViewHelper.handleValue(DefaultGrailsJsonViewHelper.groovy:326) 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:107) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1254) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1030) at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:1059) at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:1042) at org.codehaus.groovy.runtime.InvokerHelper.invokeMethodSafe(InvokerHelper.java:97) at grails.plugin.json.view.api.internal.DefaultGrailsJsonViewHelper$_getIterableWritable_closure3.doCall(DefaultGrailsJsonViewHelper.groovy:262) 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:107) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323) at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:274) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1030) at groovy.lang.Closure.call(Closure.java:427) at grails.plugin.json.view.api.internal.DefaultGrailsJsonViewHelper$2.writeTo(DefaultGrailsJsonViewHelper.groovy:278) at grails.plugin.json.view.JsonViewWritableScript.json(JsonViewWritableScript.groovy:142) at oncode_api_object__object_gson.run(oncode_api_object__object_gson:5) at grails.plugin.json.view.JsonViewWritableScript.doWrite(JsonViewWritableScript.groovy:29) at grails.views.AbstractWritableScript.writeTo(AbstractWritableScript.groovy:40) at grails.views.mvc.GenericGroovyTemplateView.renderMergedOutputModel(GenericGroovyTemplateView.groovy:73) at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:316) at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1406) at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1150) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) at javax.servlet.http.HttpServlet.service(HttpServlet.java:645) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:750) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:168) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:928) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1794) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:1583)
Trying to do other tests to pinpoint issue: I tried changing the name of the Domain class to Molecularmarker and seem to give same error. Changing name to just Marker and it works as expected.
Found the issue, leaving it here for others. In the template the name of the variable being accessed is important. In my case the template _molecularMarker was accessing an object of type MolecularMarker and the name of the variable had to be molecularMarker So model { MolecularMarker molecularMarker } json { id molecularMarker.id descripton molecularMarker.name }
g
or, you can specify the variable name, when you render the template: tmpl.molecularMarker(var: ‘marker’)
c
Thanks for the tip!
👍 1