[MAGNOLIA-6442] Guice context initialization doesn't handle dependency problems/runtime exceptions properly Created: 16/Nov/15  Updated: 01/Jul/21  Resolved: 08/Jun/21

Status: Closed
Project: Magnolia
Component/s: None
Affects Version/s: 5.4.1, 5.4.3, 5.5.5, 5.5.6, 5.5.7
Fix Version/s: 5.7.11, 6.2.10

Type: Bug Priority: Critical
Reporter: Fabrizio Giustina Assignee: Oanh Thai Hoang
Resolution: Fixed Votes: 14
Labels: VN-Implementation, maintenance, papercut
Remaining Estimate: 0d
Time Spent: 3.25h
Original Estimate: Not Specified

Issue Links:
relation
Template:
Patch included:
Yes
Acceptance criteria:
Empty
Task DoD:
[X]* Doc/release notes changes? Comment present?
[X]* Downstream builds green? [Federico Grilli]
[X]* Solution information and context easily available?
[X]* Tests
[X]* FixVersion filled and not yet released
[ ]  Architecture Decision Record (ADR)
Bug DoR:
[X]* Steps to reproduce, expected, and actual results filled
[X]* Affected version filled
Release notes required:
Yes
Date of First Response:
Sprint: Maintenance 61, Maintenance 62
Story Points: 3

 Description   

Use case: build a magnolia webapp with a missing dependency which should be used by module (e.g. take the enterprise webapp bundle and remove the geoip2-0.7.0 jar used by the personalization module). Try to start magnolia and the error log you will get is:

ERROR  info.magnolia.init.MagnoliaServletContextListener contextInitialized (MagnoliaServletContextListener.java:177) Oops, Magnolia could not be started
java.lang.NullPointerException
	at info.magnolia.objectfactory.guice.GuiceUtils.hasExplicitBindingFor(GuiceUtils.java:155)
	at info.magnolia.objectfactory.guice.GuiceComponentProvider.getComponent(GuiceComponentProvider.java:99)
	at info.magnolia.objectfactory.Components.getComponent(Components.java:97)
	at info.magnolia.context.ContextFactory.getInstance(ContextFactory.java:72)
	at info.magnolia.context.MgnlContext.getSystemContext(MgnlContext.java:368)
	at info.magnolia.context.MgnlContext.release(MgnlContext.java:629)
	at info.magnolia.context.MgnlContext.doInSystemContext(MgnlContext.java:395)
	at info.magnolia.init.MagnoliaServletContextListener.startServer(MagnoliaServletContextListener.java:247)
	at info.magnolia.init.MagnoliaServletContextListener.contextInitialized(MagnoliaServletContextListener.java:173)
	at info.magnolia.init.MagnoliaServletContextListener.contextInitialized(MagnoliaServletContextListener.java:127)
	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4992)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5490)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1575)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1565)
	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:745)

No clue about what's wrong, no info about missing classes... just a non-initialized context which has not been loaded for some reason, really hard to debug.

In order to provide a meaningful feedback I would change the build() method in GuiceComponentProviderBuilder which only catches CreationException:

        try
        {
            Injector injector = Guice.createInjector(resolveStageToUse(), module);
            return (GuiceComponentProvider) injector.getInstance(ComponentProvider.class);
        }
        catch (CreationException e) 
        {
            log.error(
                    "Magnolia failed to load module configuration with types " + configuration
                            .getTypeMapping() + " and components " + configuration
                                    .getComponents() + ". Please ensure you don't have any legacy modules present in your web application.",
                    e);
            throw e;
        }

with a catch-all ( catch (Throwable e) )... with this patch the error is definitively more useful (NB the original uncatched exception seemed to be swallowed somewhere):

ERROR  info.magnolia.objectfactory.guice.GuiceComponentProviderBuilder build (GuiceComponentProviderBuilder.java:177) Magnolia failed to load module configuration with types [...]
com.google.inject.internal.util.$ComputationException: com.google.inject.internal.util.$ComputationException: java.lang.NoClassDefFoundError: Lcom/maxmind/geoip2/DatabaseReader;
	at com.google.inject.internal.util.$MapMaker$StrategyImpl.compute(MapMaker.java:553)
	at com.google.inject.internal.util.$MapMaker$StrategyImpl.compute(MapMaker.java:419)
	at com.google.inject.internal.util.$CustomConcurrentHashMap$ComputingImpl.get(CustomConcurrentHashMap.java:2041)
	at com.google.inject.internal.FailableCache.get(FailableCache.java:50)
	at com.google.inject.internal.ConstructorInjectorStore.get(ConstructorInjectorStore.java:49)
	at com.google.inject.internal.ConstructorBindingImpl.initialize(ConstructorBindingImpl.java:125)
	at com.google.inject.internal.InjectorImpl.initializeBinding(InjectorImpl.java:507)
	at com.google.inject.internal.AbstractBindingProcessor$Processor$1.run(AbstractBindingProcessor.java:159)
	at com.google.inject.internal.ProcessedBindingData.initializeBindings(ProcessedBindingData.java:44)
	at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:122)
	at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:106)
	at com.google.inject.Guice.createInjector(Guice.java:95)
	at com.google.inject.Guice.createInjector(Guice.java:83)
	at info.magnolia.objectfactory.guice.GuiceComponentProviderBuilder.build(GuiceComponentProviderBuilder.java:171)
	at info.magnolia.objectfactory.guice.GuiceComponentProviderBuilder.build(GuiceComponentProviderBuilder.java:189)
	at info.magnolia.cms.beans.config.ConfigLoader.load(ConfigLoader.java:153)
	at info.magnolia.init.MagnoliaServletContextListener$1.doExec(MagnoliaServletContextListener.java:250)
	at info.magnolia.context.MgnlContext$VoidOp.exec(MgnlContext.java:421)
	at info.magnolia.context.MgnlContext$VoidOp.exec(MgnlContext.java:418)
	at info.magnolia.context.MgnlContext.doInSystemContext(MgnlContext.java:392)
	at info.magnolia.init.MagnoliaServletContextListener.startServer(MagnoliaServletContextListener.java:247)
	at info.magnolia.init.MagnoliaServletContextListener.contextInitialized(MagnoliaServletContextListener.java:173)
	at info.magnolia.init.MagnoliaServletContextListener.contextInitialized(MagnoliaServletContextListener.java:127)
	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4992)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5490)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1575)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1565)
	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:745)

The current behavior could really be a problem for many users, especially for anybody not using maven or integrating magnolia in complex webapps...



 Comments   
Comment by Frank Sommer [ 05/Jul/16 ]

I don't need the location trait, so I want to exclude the geoip library. It works in Magnolia 5.3.14. Why not in M5.4.7?

Comment by Thomas Duffey [ 06/Aug/20 ]

This would be a welcome small change in 6.x as well where I just spent hours tracking down why Magnolia wouldn't start.

Comment by Ji Yang [ 04/Dec/20 ]

Ya, I have the same problem in the latest version. The build() method is only handling CreationException, the rest of exception and useful information is just swallowed by the program. Also in class GuiceUtils, method hasExplicitBindingFor(), should we check the target==null at the first step? The NullPointerException always happens like this, basic mistake in java programming:

public static boolean hasExplicitBindingFor(Injector injector, Key<?> key) {
Injector target = injector;
while (true)

{ if (target.getBindings().containsKey(key)) return true; target = target.getParent(); if (target == null) return false; }


}

Comment by Oanh Thai Hoang [ 16/Jun/21 ]

Hi akhamis, Here is the solution for this ticket.

  • Prevent NPE for injector before checking explicit binding key
  • Improve log error when loading module by catching all throwable instead of just only catch CreationException as before. Example log below:
Generated at Mon Feb 12 04:14:33 CET 2024 using Jira 9.4.2#940002-sha1:46d1a51de284217efdcb32434eab47a99af2938b.