users@jersey.java.net

[Jersey] Re: Erratic missing "CdiInjecteeSkippingClassAnalyzer" Exceptions

From: Jakub Podlesak <jakub.podlesak_at_oracle.com>
Date: Wed, 23 Sep 2015 13:31:39 +0200

Hi Joachim,

Thanks for the update.

The GlassFish user mailing list (https://java.net/projects/glassfish/lists/users/archive <https://java.net/projects/glassfish/lists/users/archive>) has not been very active recently, but maybe you could
ask there for help with these EJB timing issues.

~Jakub

> On 23 Sep 2015, at 13:25, Joachim Kanbach <jo.ka_at_gmx.de> wrote:
>
> 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_at_oracle.com>
> An: users_at_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_at_gmx.de <x-msg://26/jo.ka_at_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:
>
> implemement a Jersey component provider impl (https://jersey.java.net/apidocs/2.21/jersey/org/glassfish/jersey/server/spi/ComponentProvider.html <https://jersey.java.net/apidocs/2.21/jersey/org/glassfish/jersey/server/spi/ComponentProvider.html>)
> See https://jersey.java.net/documentation/latest/user-guide.html#d0e16756 <https://jersey.java.net/documentation/latest/user-guide.html#d0e16756> for an example.
>
> 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_at_oracle.com <x-msg://26/jakub.podlesak_at_oracle.com>>
> An: users_at_jersey.java.net <x-msg://26/users_at_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 <https://java.net/jira/browse/JERSEY>)
>
> Thanks,
>
> ~Jakub
>
> On 22 Sep 2015, at 09:05, Joachim Kanbach <jo.ka_at_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)?