How do a module's classes in api/ get loaded?


I’m working on a module that depends on the Xforms module, and I’m running into a dependency problem—certain (but not all) calls to my module fail with the error that XformsService cannot be found.

XformsService is defined in xforms-api but not in xforms-omod. I have xforms-omod-4.3.5.jar loaded (as an omod). However xforms-api (I’m looking at xforms-api-4.3.5.jar) cannot be loaded as a module because it does not contain a config.xml.

How does XformsService ever become available to the OpenMRS system? This used to work with Xforms 4.3.1 but it doesn’t seem to work anymore; I’m wondering if something changed recently where modules switched from foo to foo-api/foo-omod (especially since the openmrs-sdk:install-module rule now seems to append “-omod” to the end of the module name)?

I think I’m just confused as to what the api/ directory is for. I looked at the module developer’s documentation but couldn’t find an explanation. If anyone could help out or point me at some relevant documentation that would be terrific. Many thanks!

Try expand the omod and check to see if its lib folder has the xforms api jar

Ah, that’s where it’s supposed to be. Yes, both my module and xforms-omod 4.3.5 have a copy of the xforms-api jar in the lib/ directory.

Any other ideas?

Then that should work fine. Can i look at the log? pom files? And config.xml files? Or if your module is on github, you can just point me there.

Just to make sure:

  • your module declares a dependency on xforms in its configuration.XML
  • your module has a dependency in pom.xml with scope=provided


Mysterious. It’s started working now. :frowning:

The code in question is here:

It’s now working with 4.3.5 at this commit:

It previously didn’t work with 4.3.5 at this commit:

I can’t see why one worked but not the other. You can see that I flailed around a bit trying to put the xforms-api jar into the modules directory, but that shouldn’t have made a difference, right?

1 Like

And now the error is back. (It’s definitely intermittent, perhaps due to a race condition — I restarted OpenMRS and it went away again.)

org.openmrs.api.APIException: Service not found: interface org.openmrs.module.xforms.XformsService
        at org.openmrs.api.context.ServiceContext.getService(
        at org.openmrs.api.context.Context.getService(
        at org.openmrs.module.xforms.aop.XformsConceptAdvisor.afterReturning(
        at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(
        at com.sun.proxy.$Proxy94.saveConcept(Unknown Source)

I haven’t looked inside an omod file for a long time, but the idea is that your dependent module should not include any xforms jar files.

It needs to declare it requires xforms in its config.xml and the OpenMRS class loader will give your module access to the already loaded jars that come from the xforms omod.

You also need to make sure that your pom.xml references to the xforms dependencies have scope “provided” so that the jars are not included in your build.

This turned out to be the issue: there were two copies of the xforms-api jar present, so the XformsService interface existed twice (two different interfaces named org.openmrs.module.xforms.XformsService with different memory addresses). It would be great to document this pitfall somewhere; the behaviour was pretty mysterious, and all the many layers of AOP abstraction made it quite difficult to use the debugger to understand what was happening.


1 Like

Thanks for reporting this back. Do you mind taking the initiative to document it? :slight_smile:

Hi Daniel! What’s the best place to put this information, and how would I get permission to edit it?