Resolve NullPointerException when calling service that has not yet been loaded

Update: The below is not the recommended way of waiting for services in Liferay DXP. To do it the way it should be done, please check the following documentation: https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/waiting-on-lifecycle-events

---

Sometimes, when creating a module, we may run into a situation where the service we're trying to use has not been properly loaded and tracked by OSGi yet. In such cases, the result of our service call will be a NullPointerException coming from the *ServiceUtil class, for example:

java.lang.NullPointerException
    at com.liferay.dynamic.data.mapping.service.DDMStructureLocalServiceUtil.getStructures(DDMStructureLocalServiceUtil.java:910)

Checking the line from where its thrown, we see that the only way for a NullPointerException to occur is if getService() returns null.

getService() calls the serviceTracker, which, according to its javadoc, returns null if its not tracking any service objects for that service.

Such a situation can arise if we're trying to call the service during the global.startup.events phase for example - Where OSGi is still working on registering all the services that are being loaded.

Thankfully, there's a way to resolve this issue - add a ServiceDependencyListener.

A ServiceDependencyListener, once added with one or more services, will be called once all of the services have been properly loaded and tracked.

To register a ServiceDependencyListener, just add the below:

ServiceDependencyManager serviceDependencyManager = new ServiceDependencyManager();

serviceDependencyManager.addServiceDependencyListener(new ServiceDependencyListener() {

    @Override
    public void dependenciesFulfilled() {
        _log.info("Dependencies fulfilled.");
        doWhatNeedsToBeDone();
    }

    @Override
    public void destroy() {
        // ignore
    }

});

Registry registry = RegistryUtil.getRegistry();

Filter ddmFilter = registry.getFilter("(&(objectClass=" + DDMStructureService.class.getName() + "))");

serviceDependencyManager.registerDependencies(ddmFilter);

The above is quite straightforward: Create a ServiceDependencyManager, add a new Listener with its two required methods that will be called once the dependencies are fulfilled and once the listener is no longer needed, then get the registry, construct a filter and register it as a dependency.

Hope this helps,

Daniel

Blogs
I think it is pretty annoying to do this emoticon I bumped at similar problem with FastDateFormatFactoryUtil. I wonder why portal allows and executes any action before its core services are properly started.
Hi Daniel, I was facing the same issue and this post helped a lot but I still have some problems regarding dependencies on startup events . Is there any documentation and full example about this serviceDependencyManager?

This blog post is the only mention I could found about it.

Thanks in advance emoticon
Hi Raphael,

Glad this article could help! The thing is though, this is not the recommended way of waiting for dependencies (as it turned out after I wrote this post).

The recommended way is described in the following article:

https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/waiting-on-lifecycle-events

Hope this helps!
Daniel

Could you please tell me where should I create ServiceDependencyManager? I mean in which class or it is another class which I should create ?