HTML Form Entry Velocity Expression NPE with getValueAsString(locale)

I upgraded my OpenMRS from v1.9.2 to v1.11.5 and am now getting an error using the following velocity expression:

fn.latestObs(1088).getValueAsString(pt)

The stack trace is:

ERROR - FormEntrySession.evaluateVelocityExpression(383) |2016-06-07 13:59:48,801| Exception evaluating velocity expression
org.apache.velocity.exception.MethodInvocationException: Invocation of method 'getValueAsString' in  class org.openmrs.Obs threw exception java.lang.NullPointerException at org.openmrs.module.htmlformentry.FormEntrySession[line 1, column 23]
	at org.apache.velocity.runtime.parser.node.ASTMethod.handleInvocationException(ASTMethod.java:337)
	at org.apache.velocity.runtime.parser.node.ASTMethod.execute(ASTMethod.java:284)
	at org.apache.velocity.runtime.parser.node.ASTReference.execute(ASTReference.java:252)
	at org.apache.velocity.runtime.parser.node.ASTReference.render(ASTReference.java:332)
	at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:336)
	at org.apache.velocity.runtime.RuntimeInstance.render(RuntimeInstance.java:1277)
	at org.apache.velocity.runtime.RuntimeInstance.evaluate(RuntimeInstance.java:1216)
	at org.apache.velocity.runtime.RuntimeInstance.evaluate(RuntimeInstance.java:1165)
	at org.apache.velocity.app.VelocityEngine.evaluate(VelocityEngine.java:219)
	at org.openmrs.module.htmlformentry.FormEntrySession.evaluateVelocityExpression(FormEntrySession.java:375)
	at org.openmrs.module.htmlformentry.handler.VelocityHandler.getSubstitution(VelocityHandler.java:29)
	at org.openmrs.module.htmlformentry.handler.SubstitutionTagHandler.doStartTag(SubstitutionTagHandler.java:39)
	at org.openmrs.module.htmlformentry.HtmlFormEntryGenerator.applyTagsHelper(HtmlFormEntryGenerator.java:516)
	at org.openmrs.module.htmlformentry.HtmlFormEntryGenerator.applyTagsHelper(HtmlFormEntryGenerator.java:533)
	at org.openmrs.module.htmlformentry.HtmlFormEntryGenerator.applyTagsHelper(HtmlFormEntryGenerator.java:533)
	at org.openmrs.module.htmlformentry.HtmlFormEntryGenerator.applyTagsHelper(HtmlFormEntryGenerator.java:533)
	at org.openmrs.module.htmlformentry.HtmlFormEntryGenerator.applyTagsHelper(HtmlFormEntryGenerator.java:533)
	at org.openmrs.module.htmlformentry.HtmlFormEntryGenerator.applyTagsHelper(HtmlFormEntryGenerator.java:533)
	at org.openmrs.module.htmlformentry.HtmlFormEntryGenerator.applyTagsHelper(HtmlFormEntryGenerator.java:533)
	at org.openmrs.module.htmlformentry.HtmlFormEntryGenerator.applyTagsHelper(HtmlFormEntryGenerator.java:533)
	at org.openmrs.module.htmlformentry.HtmlFormEntryGenerator.applyTagsHelper(HtmlFormEntryGenerator.java:533)
	at org.openmrs.module.htmlformentry.HtmlFormEntryGenerator.applyTagsHelper(HtmlFormEntryGenerator.java:533)
	at org.openmrs.module.htmlformentry.HtmlFormEntryGenerator.applyTags(HtmlFormEntryGenerator.java:489)
	at org.openmrs.module.htmlformentry.FormEntrySession.createForm(FormEntrySession.java:413)
	at org.openmrs.module.htmlformentry.FormEntrySession.getHtmlToDisplay(FormEntrySession.java:768)
	at org.openmrs.module.htmlformentry.web.controller.HtmlFormEntryController.getFormEntrySession(HtmlFormEntryController.java:202)
	at sun.reflect.GeneratedMethodAccessor981.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:162)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:440)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:428)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:844)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:829)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.openmrs.module.web.filter.ForcePasswordChangeFilter.doFilter(ForcePasswordChangeFilter.java:61)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:72)
	at org.openmrs.module.web.filter.ModuleFilter.doFilter(ModuleFilter.java:54)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.openmrs.web.filter.OpenmrsFilter.doFilterInternal(OpenmrsFilter.java:109)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:230)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
	at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
	at sun.util.locale.provider.LocaleProviderAdapter.getAdapter(LocaleProviderAdapter.java:245)
	at java.text.NumberFormat.getInstance(NumberFormat.java:859)
	at java.text.NumberFormat.getNumberInstance(NumberFormat.java:469)
	at org.openmrs.Obs.getValueAsString(Obs.java:965)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.doInvoke(UberspectImpl.java:389)
	at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.invoke(UberspectImpl.java:378)
	at org.apache.velocity.runtime.parser.node.ASTMethod.execute(ASTMethod.java:270)
	... 85 more

The workaround is to change getValueAsString(pt) to valueCoded.name:

fn.latestObs(1088).valueCoded.name

I have HTML Form Entry v2.6 installed. Is there anything else that needs to be done to get my velocity expression working again?

1 Like

Was the exact same expression and for the same concept id working well before the upgrade?

1 Like

Yup, exact same form was working before the upgrade, but now the velocity expression throws an NPE.

It now makes sense because this change was introduced in 1.11.x

This is caused by passing a null locale in fn.latestObs(1088).getValueAsString(null) The other alternative would be for the platform to use Context.getLocale() whenever the locale parameter is null.

We are are passing pt as the locale though, not null. Maybe pt never actually worked, but the platform was handling it properly?

What can we do from our side @dkayiwa? It would be best for us not to have to update all our forms with the workaround :slight_smile:.

I think pt always ended up as null in Obs.getValueAsString()

It is just that platform 1.11.x add some code that never expected it to be null. :slight_smile:

So we may need to look down the pipeline to see how pt turns into a locale.

@steliomo can you try this: fn.latestObs(1088).getValueAsString($!{locale})

1 Like

@dkayiwa it works. in this case, when you use $!{locale} is to grab the locale Object as the method getValueAsString expects right?

1 Like

That is correct!

1 Like

Perfect @dkayiwa. Thanks.

By the way can I have your skype or email?

Cheers

Here is a summary of what happened:

  1. The eSaude community built our forms on v1.9.2 using the velocity expression:

    fn.latestObs(1088).getValueAsString(pt);
    

    The reason this syntax was used is possibly due to this comment. The docs do not say this syntax is supported.

  2. What the HTML Form Entry Module was (and still is) doing is resolve pt to null and thus calll the method as follows:

    fn.latestObs(1088).getValueAsString(null);
    
  3. Obs.getValueAsString() correctly handled null for the locale parameter until this commit.

  4. After we upgraded OpenMRS core to v1.11.x, this line started throwing a NPE.


**Solution:** Use the correct syntax for the velocity expression:
fn.latestObs(1088).getValueAsString($!{locale})
```

or

```java
fn.latestObs(1088).valueCoded.name
```
1 Like