users@jersey.java.net

[Jersey] Re: Erratic missing "CdiInjecteeSkippingClassAnalyzer" Exceptions

From: Joachim Kanbach <jo.ka_at_gmx.de>
Date: Wed, 23 Sep 2015 13:25:21 +0200
Hi Jakub,
 
I have an update. "Fortunately", the error occured again last night so the code I had inserted trying to deal with it was executed.
 
As I was under the assumption that I'd disable CDI injection as a whole using your suggestion, and due to the impossibility to do that as explained in my other reply, I have instead added a try-catch block around the call to the stateless EJB catching the EJBException. In the exception handling, I let the thread sleep for 5 seconds and then simply retry the method call (at most once). And what can I say, this second call runs perfectly fine without any errors, i.e. all the injections and EJB creations work.
 
So I find my guess confirmed that it is some sort of unfortunate timing/early/eager initialization that causes this error (using @Startup, @Singleton, @Asynchronous). If I knew which component is lagging behind here and how to query its state, I'd be able to wait for that to finish instead of a fixed time.
 
I had also added a javax.enterprise.inject.spi.Extension that observes the various CDI lifecycle events (BeforeBeanDiscovery, AfterTypeDiscovery, AfterBeanDiscovery, AfterDeploymentValidation), but I forgot to adapt the build process so that the required file META-INF/services/javax.enterprise.inject.spi.Extension wasn't bundled with the WAR file. Therefore, I can't tell anything from the server log about the CDI initialization state. I will post this information later if I have it.
 
Gesendet: Dienstag, 22. September 2015 um 11:55 Uhr
Von: "Jakub Podlesak" <jakub.podlesak@oracle.com>
An: users@jersey.java.net
Betreff: [Jersey] Re: Erratic missing "CdiInjecteeSkippingClassAnalyzer" Exceptions
Hi Joachim,
 
Please see inline…
 
On 22 Sep 2015, at 11:11, Joachim Kanbach <jo.ka@gmx.de> wrote:
 
Hi Jakub,
 
thank your for your reply.
 
I have enabled CDI support in this module, in fact my beans.xml even declares a CDI interceptor. In those cases when the deployment and server startup code triggered by that singleton EJB run fine, CDI injection (in other beans) works without any problems thereafter.
 
I can confirm that the exception only occurs quite rarely; unfortunately the consequences when it does occur are quite bad because the singleton EJB is not available anymore then. I was thinking to catch the EJBException explicitly around this call so at least the bean will still be available. I could also add some logging in the catch clause to analyze the current server state wrt. CDI initialization etc. What would be useful information for you and how could I get hold of it? I'm still trying hard to reproduce it on my development system without success.
 
Well, you can try to search your server log for something like:
WARNING: Could not load service class org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider
 
If you see such a log message before you get a failure, that would confirm how it happens.
 
 
Since there's no immediate explanation, here are some more details of my design: that startup/singleton EJB actually spawns a different thread by registering a java.nio.file.WatchService in an @Asynchronous method, which is then triggered by a file on the file system present at server startup (I know using java.nio.file is not covered by the Java EE specification, but this is required/convenient for our environment and didn't cause any other problems yet). So it's one of the GlassFish EJB thread pool threads where the exception happens:
 
[2015-09-17T20:38:15.041+0200] [glassfish 4.1] [WARNING] [] [javax.enterprise.ejb.container] [tid: _ThreadID=114 _ThreadName=__ejb-thread-pool1] [timeMillis: 1442515095041] [levelValue: 900] [[
javax.ejb.EJBException: javax.ejb.EJBException: javax.ejb.CreateException: Could not create stateless EJB
 
Another thing that might be of importance is that I use @ExcludeDefaultInterceptors on both the singleton and the called stateless EJB.
 
And finally, what I find confusing is that I don't even use CDI injection in any of those classes involved in the issue. The stateless EJB is injected with @EJB into the singleton, and both the singleton and the stateless EJB only have other @EJB, @PersistenceContext and @Resource (javax.annotation.Resource) annotations.
 
Since you do not use any CDI injection, there should be a workaround for you:
 
 
The only important method that you need to implement is initialize:
 
    @Override
    public void initialize(final ServiceLocator locator) {
 
        final ClassAnalyzer defaultClassAnalyzer =
                locator.getService(ClassAnalyzer.class, ClassAnalyzer.DEFAULT_IMPLEMENTATION_NAME);
 
        final DynamicConfiguration dc = Injections.getConfiguration(locator);
 
        final ScopedBindingBuilder bindingBuilder =
                Injections.newBinder(defaultClassAnalyzer);
 
        bindingBuilder.analyzeWith(ClassAnalyzer.DEFAULT_IMPLEMENTATION_NAME)
                .to(ClassAnalyzer.class)
                .named(“CdiInjecteeSkippingClassAnalyzer");
 
        Injections.addBinding(bindingBuilder, dc);
 
        dc.commit();
    }
 
 your bind method should always return false.
 
You need to register your component provider in a META-INF/services registry and bundle it with your application.
 
I have not tested, but the above workaround should hopefully help.
 
~Jakub
 
 
 
 
Regards,
Joachim
 
Gesendet: Dienstag, 22. September 2015 um 09:58 Uhr
Von: "Jakub Podlesak" <jakub.podlesak@oracle.com>
An: users@jersey.java.net
Betreff: [Jersey] Re: Erratic missing "CdiInjecteeSkippingClassAnalyzer" Exceptions
Hi Joachim,
 
We bumped into a similar issue already in a different container.
 
The problem happens if you disable CDI support. Then EJB integration breaks.
I do not understand why you can see the issue only occasionally. Could you please double check?
 
Then to enable CDI, it should be sufficient to insert an empty beans.xml file into your application: <beans/>
 
Could you please try the above suggested workaround, and eventually file a bug with a simple
reproducer application attached? (https://java.net/jira/browse/JERSEY)
 
Thanks,
 
~Jakub
 
On 22 Sep 2015, at 09:05, Joachim Kanbach <jo.ka@gmx.de> wrote:
 
I hope this is the right mailing list to ask since my problem is apparently in the Jersey-GlassFish integration layer (jersey-gf-cdi.jar/jersey-gf-ejb.jar).
 
I have a setup where a @Singleton @Startup EJB makes calls to another @Stateless EJB. Due to the program layout, it's possible that those calls are triggered right at the server startup through the @PostConstruct method (the whole architecture is a little more complex, I can give the deails if required, but I first need guidance where to look for clues at all).
 
On our build system, the nightly build and deploy occasionally fails with a stack trace like this:
 
javax.ejb.EJBException: javax.ejb.EJBException: javax.ejb.CreateException: Could not create stateless EJB
        at com.sun.ejb.containers.StatelessSessionContainer._getContext(StatelessSessionContainer.java:435)
        at com.sun.ejb.containers.BaseContainer.getContext(BaseContainer.java:2579)
        at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1971)
        at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:210)
        at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
        at com.sun.proxy.$Proxy224.deleteKeyMetaMappingByDbid(Unknown Source)
        at com.mycompany.cfg.__EJB31_Generated__ConfigurationService__Intf____Bean__.deleteKeyMetaMappingByDbid(Unknown Source)
        [...]
Caused by: javax.ejb.EJBException: javax.ejb.CreateException: Could not create stateless EJB
        [...]
Caused by: javax.ejb.CreateException: Could not create stateless EJB
        [...]
Caused by: A MultiException has 1 exceptions.  They are:
1. java.lang.IllegalStateException: Could not find an implementation of ClassAnalyzer with name CdiInjecteeSkippingClassAnalyzer
        at org.jvnet.hk2.internal.Collector.throwIfErrors(Collector.java:88)
        at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:928)
        at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:902)
        at org.glassfish.jersey.gf.ejb.internal.EjbComponentInterceptor.inject(EjbComponentInterceptor.java:71)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        [...]
Caused by: java.lang.IllegalStateException: Could not find an implementation of ClassAnalyzer with name CdiInjecteeSkippingClassAnalyzer
        at org.jvnet.hk2.internal.ServiceLocatorImpl.getAnalyzer(ServiceLocatorImpl.java:2249)
        at org.jvnet.hk2.internal.Utilities.getClassAnalyzer(Utilities.java:172)
        at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:927)
        ... 102 more
 
"ConfigurationService" is the @Stateless EJB on which deleteKeyMetaMappingByDbid() should be called
 
This happens quite rarely, not more than once a week or so. I didn't manage to recreate the situation outside of the build period. It could be that the system is under very high load during that time. But I couldn't find a pattern that separates the successful deployments, where the exact same sequence of method calls and EJB creations happens, from the ones failing with this stack trace.
 
I've looked at the source code a little and realized that "CdiInjecteeSkippingClassAnalyzer" must be the HK2 internal name used for org.glassfish.jersey.gf.cdi.internal.InjecteeSkippingAnalyzer. But if you search for this on the web, you get only a very few hits, none of which is helpful.
 
So my question is how an error like this could be possible at all? I was wondering if the cause might be that HK2 may not have finished initializing properly before the @Stateless EJB is to be injected and used (cf. my remark regarding system load)?