-
Notifications
You must be signed in to change notification settings - Fork 113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mojarra fails to initialize when BDA is empty according to Weld #5238
Conversation
@manovotn see here for a practical need to have a standard way to "init" CDI in container mode. |
Looking at the issue, the user app has no need for CDI container as such, so why start it? |
Many of Mojarra's internals are based on CDI. So when we activate Faces (which happens conditionally), we always also need CDI. |
weld.onStartup(null, servletContext); | ||
result = (BeanManager) applicationMap.get("org.jboss.weld.environment.servlet.jakarta.enterprise.inject.spi.BeanManager"); | ||
} catch (Exception | LinkageError e) { | ||
LOGGER.log(WARNING, "Reinitializing Weld failed - giving up, please make sure your project has at least one @Named bean and retry", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think @Named
is enough here.
If I understand correctly what you're running into, there are two factors in play. Firstly it's the discovery mode the app uses (all
or annotated
, the latter being default from CDI 4.0). Secondly, if it's annotated
, then you need to have some bean with bean defining annotation[1][2]; @Named
isn't bean defining.
I assume you're hitting this only with annotated
discovery (since with all
you're likely to find something that could be a bean), so you could log something like:
"Reinitializing Weld failed - giving up, please make sure your project contains at least one bean class with a bean defining annotation and retry"
[1] https://jakarta.ee/specifications/cdi/4.0/jakarta-cdi-spec-4.0.html#bean_defining_annotations
[2] https://jakarta.ee/specifications/cdi/4.0/jakarta-cdi-spec-4.0.html#bean_defining_annotations_full
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Point taken, fixed.
ServletContext servletContext = (ServletContext) facesContext.getExternalContext().getContext(); | ||
servletContext.setInitParameter("org.jboss.weld.environment.servlet.archive.isolation", "false"); | ||
ServletContainerInitializer weld = (ServletContainerInitializer) Class.forName("org.jboss.weld.environment.servlet.EnhancedListener").getConstructor().newInstance(); | ||
weld.onStartup(null, servletContext); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BalusC is this basically just for detection purposes? Assuming Weld bootstrap fails the first time around, re-triggering it for the exact same deployment will have the same result.
If it's detection only, perhaps we could instead use ServletContext#setInitParameter()
on Weld side which you can then detect here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this basically just for detection purposes? [...] re-triggering it for the exact same deployment will have the same result.
No, it will actually fix the issue. See also attached ticket.
(taken from the linked issue)
Hmm, Weld's bootstrap is determined by the need of user app as that's the deployment (WAR) we get to scan. I don't think we want to change the default behavior though. Also, I can see Mojarra itself has some CDI parts, namely at least a CDI extension and several other modules declaring |
As internals of Faces are required to be CDI based, every Faces implementation would need this. There is basically only one other Faces implementation, and that is indeed MyFaces. I don't think though scanning It would be unreasonable for CDI to execute this algorithm, as its spec defined and would tie the CDI spec to the Faces spec. As CDI is the lower level in the EE architecture, this is unwanted. Extra complexity is introduced by EE not defining how and in which order CDI and Faces are initialised. Some containers (probably most) use a What could maybe work is an extra static method for Thoughts? |
Right, that's what I thought.
What's the point of re-executing it? If the CDI container detected a state that prevented it from booting, it will simply do so again. The method won't allow you to change the deployment setup (nor can it due to variety of envs it can be invoked from).
Can you please point me to relevant spec parts? I don't mean to sound rude, I just want to check.
So I take it you couldn't provide some servlet context parameter for this? This seems more and more like an issue in servlet, so any servlet specific solution would also do the trick I suppose. I am not well versed there tho, so I am open to suggestions :) |
It should do pretty much what the container did to init CDI when loading the application that uses Faces. The concept of an "application" (and with it the application scope etc) should be well enough defined by both Faces and Servlet.
I tested this on a patched Weld, and it won't. Since at that point the above mentioned flag would have been set to true, and it would continue booting. At least for Weld (which I patched and tested a while ago) this worked on GlassFish, Piranha Cloud and Tomcat. For Piranha Cloud and Tomcat (which mainly use the Weld Provided WeldInitListener from org.jboss.weld.servlet:weld-servlet-core) I did "cheat" somewhat by adding a dummy class to the BDA at that point.
Several features depend on CDI, for instance:
But more importantly, implicit object now must be resolved via CDI: This is what may trigger the error in many cases. People use a Facelet, which uses some expression language, and for some reason or the other, they don't have a CDI bean in their application. Faces will now internally try to resolve via CDI, but that fails if Weld thought it didn't need to continue booting.
Faces uses CDI internally. And the plans are to increase that usage. I.e. Faces uses many factories to obtain a lot of internal instances of things (like the lifecycle instance, the view instance, you name it). We'd like to remove many of these and use CDI instead. The application does not have to explicitly use CDI in order for CDI to be needed by Faces. |
Partially if CDI states that within a container that supports Servlet, CDI must be initialised using a Then, Faces could use two ServletContainerInitializers to sandwich itself around the CDI one. The first one would run the Faces detection algorithm that sets a flag which CDI then must pick up and init itself even when no beans are found in the application BDA. That requires multiple changes though to both the Servlet spec (e.g. logical names for ServletContainerInitializers and before and after ordering) and the change for the CDI spec to honour said flag / parameter and the ServletContainerInitializer requirement. |
ps. In general this also highlight a major issue among specs in EE. Several things that Faces once did itself have been extracted to separate specs, among which Expression Language and CDI itself (partially, in a way). But then those extracted specs don't understand the requirements of the specs they came from and/or which depend on them. A lot of time is then spend convincing people that run those other specs of those things, which are relatively obvious to the depending spec. The alternative is that Faces introduces its own bean model again, so we can simply arrange those things ourselves, but that's a major step back. I'm not sure how to solve this. We can't expect the CDI team to know about the intricate details in Faces, Security, REST, etc, but the current situation is not optimal either. |
I see, in this regard you are basically a "consumer" of CDI functionality just as much as user app is (or can be).
Right, good point.
I am not sure either, any solution would be impl specific because this is an issue specific to servlets (since EE server boots whole CDI, I suppose they can simply choose to do that based on presence of Faces) and CDI spec doesn't cover pure servlet approach anyway. |
Improved warning message
'Fail fast' line should be in ConfigureListener because ordering of ServletContainerInitializer is undefined
To me the best way is to improve Servlet API to detect and init CDI Faces integrate Servlets, Filters and CDI to simplify I think that there is a similar problem with JPA / CDI / JTA .... At the moment the biggest problem of Jakarta EE is the lack To me (as a developer) the "Jakarta EE framework" should |
weld.onStartup(null, servletContext); | ||
result = (BeanManager) applicationMap.get("org.jboss.weld.environment.servlet.jakarta.enterprise.inject.spi.BeanManager"); | ||
} catch (Exception | LinkageError e) { | ||
LOGGER.log(WARNING, "Reinitializing Weld failed - giving up, please make sure your project has at least one @Named bean and retry", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
has at least one @nAmed bean and retry
Doens't have to be an @Named
bean. Any enabled Bean counts.
We probably need something more/better in the future, but let's do it this way for now. |
#5232