Introduction
JSF was since version 2.2 moving towards CDI for bean management. Since JSF 2.2, as part of Java EE 7, there's the new CDI compatible @ViewScoped
and there's the CDI-only @FlowScoped
which doesn't have an equivalent for @ManagedBean
. Since JSF 2.3, as part of Java EE 8, the @ManagedBean
and associated scopes from javax.faces.bean
package are deprecated in favor of CDI.
Now, there are some JSF / Jakarta Faces users using Tomcat which does as being a barebones JSP/Servlet container not support CDI out the box (also not JSF, you know, you had to supply JSF JARs yourself). If you intend to use CDI on Tomcat, the most straightforward step would be to upgrade it to TomEE. It's exactly like Tomcat, but then with among others OpenWebBeans on top of it, which is Apache's CDI implementation. TomEE installs as easy as Tomcat: just download the ZIP and unzip it. TomEE integrates in Eclipse as easy as Tomcat: just use existing Tomcat server plugin. As a bonus, TomEE also comes with EJB and JPA, making services and DB interaction a breeze.
However, perhaps you just have no control over upgrading the server. In that case, you'd like to supply CDI along with the webapp itself then in flavor of some JARs and additional configuration entries/files. So far, there are 2 major CDI implementations: Weld (the reference implementation) and OpenWebBeans. We'll treat them both in this article.
Install Weld in Tomcat 10+ (last updated: 13 July 2024)
Tomcat 10.0.x is the first version to be "Jakartified", i.e. it's using jakarta.*
package instead of javax.*
package for the API classes. It is using Servlet 5.0 API of Jakarta EE 9. Tomcat 10.1.x is the second Jakartified version, using Servlet 6.0 API of Jakarta EE 10.
In order to install CDI on Tomcat 10.x, perform the following steps:
- For Tomcat 10.1.x, drop
weld-servlet-shaded.jar
of version 5.x in webapp's/WEB-INF/lib
. In case you're using Maven, this is the coordinate:<dependency> <groupId>org.jboss.weld.servlet</groupId> <artifactId>weld-servlet-shaded</artifactId> <version>5.1.2.Final</version> </dependency>
For Tomcat 10.0.x, useweld-servlet-shaded.jar
of version 4.x instead:<dependency> <groupId>org.jboss.weld.servlet</groupId> <artifactId>weld-servlet-shaded</artifactId> <version>4.0.3.Final</version> </dependency>
- Create a
/META-INF/context.xml
file in webapp's web content with following content (or, if you already have one, add just the<Resource>
entry to it):<Context> <Resource name="BeanManager" auth="Container" type="jakarta.enterprise.inject.spi.BeanManager" factory="org.jboss.weld.resources.ManagerObjectFactory" /> </Context>
This will register Weld'sBeanManager
factory in Tomcat's JNDI. This cannot be performed programmatically by Weld because Tomcat's JNDI is strictly read-only. This step is not necessary for Mojarra and OmniFaces because both libraries are able to find it inServletContext
instead. However, there may be other libraries which still expect to findBeanManager
in JNDI, so you'd then best keep this configuration file anyway for those libraries. - Create a (empty)
/WEB-INF/beans.xml
file (no, not in/META-INF
! that's only for inside JAR files such as OmniFaces). - Optionally: if you also want to use JSR-303 Bean Validation (
@NotNull
and friends), then dropjakarta.validation-api.jar
of version 3.0.x andhibernate-validator.jar
of version 8.0.x in webapp's/WEB-INF/lib
, or use below Maven coordinate:<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.1.Final</version> </dependency>
For Tomcat 10.0.x, usehibernate-validator.jar
of version 7.0.x instead.
Now your webapp is ready for CDI in Tomcat 10+ via Weld!
Install Weld in Tomcat 9- (last updated: 1 Dec 2022)
The difference with Tomcat 10+ is that Tomcat 9- still uses the old javax.*
package instead of the new jakarta.*
package. This is not compatible with Weld 4+, you need Weld 3 instead. Perform the following steps:
- Drop
weld-servlet-shaded.jar
of version 3.x in webapp's/WEB-INF/lib
. In case you're using Maven, this is the coordinate:<dependency> <groupId>org.jboss.weld.servlet</groupId> <artifactId>weld-servlet-shaded</artifactId> <version>3.1.9.Final</version> </dependency>
- Create
/META-INF/context.xml
file in webapp's web content with following content (or, if you already have one, add just the<Resource>
entry to it):<Context> <Resource name="BeanManager" auth="Container" type="javax.enterprise.inject.spi.BeanManager" factory="org.jboss.weld.resources.ManagerObjectFactory" /> </Context>
This will register Weld'sBeanManager
factory in Tomcat's JNDI. This cannot be performed programmatically by Weld because Tomcat's JNDI is strictly read-only. This step is not necessary if you're targeting at least Mojarra 2.2.11 and/or OmniFaces 2.4 or newer. Both are able to find it inServletContext
instead. However, there may be other libraries which still expect to findBeanManager
in JNDI, you'd then best keep this configuration file anyway for those libraries. - Create a (empty)
/WEB-INF/beans.xml
file (no, not in/META-INF
! that's only for inside JAR files such as OmniFaces). - Only if your
web.xml
is declared conform Servlet version 4.0 instead of 3.1, then you also need to put the@javax.faces.annotation.FacesConfig
annotation on an arbitrary CDI managed bean somewhere in the project (usually the one representing the "application-wide config" would be OK).package com.example; import javax.enterprise.context.ApplicationScoped; import javax.faces.annotation.FacesConfig; @FacesConfig @ApplicationScoped public class Config { }
It is indeed utterly unnecessary, but it is what it is. - Optionally: if you also want to use JSR-303 Bean Validation (
@NotNull
and friends), then dropjakarta.validation-api.jar
andhibernate-validator.jar
in webapp's/WEB-INF/lib
, or use below Maven coordinate:<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.2.5.Final</version> </dependency>
Now your webapp is ready for CDI in Tomcat 9- via Weld! Note that in previous Weld versions you needed to register a <listener>
in web.xml
. This is not necessary anymore with at least Weld 2.2.0 on a "recent" Tomcat 9- version!
Install OpenWebBeans in Tomcat 10+ (last updated: 13 July 2024)
- This is easiest with Maven as OpenWebBeans has quite some sub-dependencies. Here are the coordinates:
<dependency> <groupId>org.apache.openwebbeans</groupId> <artifactId>openwebbeans-jsf</artifactId> <version>4.0.2</version> </dependency> <dependency> <groupId>org.apache.openwebbeans</groupId> <artifactId>openwebbeans-el22</artifactId> <version>4.0.2</version> </dependency>
- Create
/META-INF/context.xml
file in webapp's web content with following content (or, if you already have one, add just the<Resource>
entry to it):<Context> <Resource name="BeanManager" auth="Container" type="jakarta.enterprise.inject.spi.BeanManager" factory="org.apache.webbeans.container.ManagerObjectFactory" /> </Context>
This will register OpenWebBeans'BeanManager
factory in Tomcat's JNDI. This cannot be performed programmatically by OpenWebBeans because Tomcat's JNDI is strictly read-only. - Add the below
<listener>
entry to webapp'sweb.xml
:<listener> <listener-class>org.apache.webbeans.servlet.WebBeansConfigurationListener</listener-class> </listener>
This will make sure that OpenWebBeans initializes before Jakarta Faces, otherwise you may face ajava.lang.IllegalStateException: It's not allowed to call getBeans(Type, Annotation...) before AfterBeanDiscovery
. - Create a (empty)
/WEB-INF/beans.xml
file (no, not in/META-INF
! that's only for JARs such as OmniFaces). - Optionally: if you also want to use JSR-303 Bean Validation (
@NotNull
and friends), add the below Maven coordinate:<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.1.Final</version> </dependency>
Now your webapp is ready for CDI in Tomcat 10+ via OpenWebBeans!
Install OpenWebBeans in Tomcat 9- (last updated: 3 January 2021)
The difference with Tomcat 10+ is that Tomcat 9- still uses the old javax.*
package instead of the new jakarta.*
package. Perform the following steps:
- This is easiest with Maven as OpenWebBeans has quite some sub-dependencies. Here are the coordinates (do note that it also includes JSR-303 Bean Validation API as without it OpenWebBeans would unexpectedly fail deployment with
java.lang.TypeNotPresentException: Type javax.validation.ConstraintViolation not present
caused byjava.lang.ClassNotFoundException: javax.validation.ConstraintViolation
):<dependency> <groupId>javax.enterprise</groupId> <artifactId>cdi-api</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>org.apache.openwebbeans</groupId> <artifactId>openwebbeans-jsf</artifactId> <version>2.0.20</version> </dependency> <dependency> <groupId>jakarta.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.2</version> </dependency>
- Create
/META-INF/context.xml
file in webapp's web content with following content (or, if you already have one, add just the<Resource>
entry to it):<Context> <Resource name="BeanManager" auth="Container" type="javax.enterprise.inject.spi.BeanManager" factory="org.apache.webbeans.container.ManagerObjectFactory" /> </Context>
This will register OpenWebBeans'BeanManager
factory in Tomcat's JNDI. This cannot be performed programmatically by OpenWebBeans because Tomcat's JNDI is strictly read-only. - Add the below
<listener>
entry to webapp'sweb.xml
:<listener> <listener-class>org.apache.webbeans.servlet.WebBeansConfigurationListener</listener-class> </listener>
This will make sure that OpenWebBeans initializes before OmniFaces, otherwise you may face ajava.lang.IllegalStateException: It's not allowed to call getBeans(Type, Annotation...) before AfterBeanDiscovery
. - Create a (empty)
/WEB-INF/beans.xml
file (no, not in/META-INF
! that's only for JARs such as OmniFaces). - Optionally: if you also want to use JSR-303 Bean Validation (
@NotNull
and friends), add the below Maven coordinate:<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.2.0.Final</version> </dependency>
Now your webapp is ready for CDI in Tomcat 9- via OpenWebBeans!
40 comments:
+1 great post BalusC! I like your reference to TomEE and OpenWebBeans (Apache's CDI implementation). :)
Great post BalusC. Lots of your post helped me. By the way can you also help me with this one? http://stackoverflow.com/questions/19681933/embed-pdf-in-webpage
Thanks for your posts, BalusC! They are all great!
Have you tried it in a production enviroment? :) It's ok?
The Weld guide I just downloaded from the Weld site specifies two listeners to be added for tomcat:
'org.jboss.weld.servlet.WeldInitialListener' and 'org.jboss.weld.servlet.WeldTerminalListener'. I tried that and it didn't work. However, yours works. Is it an outdated method in the guide?
Hi BalusC - first, thanks so much for being an expert and for sharing your knowledge to help others.
I tried everything exactly as you posted and I have a custom constraint in jee 6 - but for some reason it's not called? when i attempt to submit the form with a button, my fieldValidator is not called - any idea why that could be?
thanks!
Are you 100% positive that this is all what is required? I'm getting a
SEVERE: Exception sending request initialized lifecycle event to listener instance of class com.sun.faces.config.ConfigureListener
java.lang.UnsupportedOperationException
at javax.faces.context.FacesContext.getExceptionHandler(FacesContext.java:287)
at javax.faces.event.ExceptionQueuedEventContext.getListenersForEventClass(ExceptionQueuedEventContext.java:262)
[..]
when giving it a try using Tomcat 7.0.x, JSF Mojarra 2.2.5 and weld-servlet 2.1.0.
[..] using the "simplegreeting" example of JavaEE 6 tutorial as (natural) starting point.
Btw, which is your starting point? Would be good to be able to download the example project somehow/somewhere.
Ok, got it working by adding the "Faces Servlet" servlet to web.xml. As it turns out, JavaEE is probably not the best starting point.
Note that newer versions of Weld throw the following exception when the org.jboss.weld.environment.servlet.Listener is not configured:
javax.naming.NamingException: WELD-001300: Unable to locate BeanManager
at org.jboss.weld.resources.ManagerObjectFactory.getObjectInstance(ManagerObjectFactory.java:52)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:304)
Also, besides Weld and OpenWebBeans there's a third CDI implementation called CanDI (it's natively used by Caucho's Resin).
Hello Balusc,
Thanks for this post, is it possible to install WELD instead of OpenWebBeans for TomEE ?
Muito bom, obrigado pela dica.
I have tried to configure tomcat 7.0.50 to work with Weld( weld-servlet 2.2.6), but I am getting a strange java.lang.NoSuchMethodError: com.sun.faces.util.Util.isCdiOneOneOrGreater()Z
I am using it with a java webapp with jsf 2.2 + omnifaces
@Moses: The webapp's runtime classpath is polluted with a duplicate JSF (Mojarra) impl JAR file of an older version lacking that method, e.g. 2.0 or 2.1. Just cleanup it.
Really nice article which has saved me quite a lot of time. I would just like to state that when you use a decently up to date version of Tomcat 7 (or Tomcat 8, or any other servlet 3.0 compatible container) you don't actually need to configure any listener, it will just magically work.
We package our code in multiple jars under WEB-INF/lib. Does every jar need a beans.xml file?
Awesome BalusC!!! Great post, was very useful for me. Thank you very much
I also had to add the dependency org.jboss:jandex:1.2.3.Final to get Weld up and running.
OWB docs are better now ;)
http://openwebbeans.apache.org
Thanks!!! Love you.
Simplesmente perfeito!
Você salvou minha vida.
Muiito obrigado!
Great post! Tks!
Well done... Great post... I use CDI env in my work but i couldn't understand why we were using Widfly. But now, reading your post, i got it.
Thanks...
It doesn't work with weld-servlet-2.3.3.Final.jar and cdi-api-1.2.jar. I am still getting an checkCDIAvailable error.
Thanks for the post. I wrote a 'hello-CDI-on-java-SE-world' project for me to learn the techniques exposed here and elsewhere.
For those that maybe interested: https://github.com/aequologica/hello-CDI-on-java-SE-world
The code is live here: https://tebaldi051108trial.hanatrial.ondemand.com/modules/cdi/ (at least at this very moment, may not be live for ever)
Thanks!
In fact, the live example for 'hello-CDI-on-java-SE-world' has just changed : https://tebaldi051108trial.hanatrial.ondemand.com/lifebuoy/cdi.jsp
Many thanks)))
Thanks BalusC for this post.
I am using WELD 2.4.1.Final for my web application running on Tomcat 7. I am having JSF and Jax-RS Rest services in my web application. I have implemented asynchronous JAX-RS Rest Services. Async Rest call works perfect, but in logs I got following Warnings :
WELD-000715: HttpContextLifecycle guard not set. The Servlet container is not fully compliant.
WELD-000714: HttpContextLifecycle guard leak detected. The Servlet container is not fully compliant. The value was 1
WELD-000335: Conversation context is already active, most likely it was not cleaned up properly during previous request processing
I got from this website : http://weld.cdi-spec.org/documentation/, that these are issues from Tomcat.
Should I consider them or just ignore? If I ignore, does it affect performance of my web app? Is there any Workaround to get rid of this warnings?
Hey BalusC! First of all I want to thank you for sharing your expertise on these matters. Since I started using JSF for my projects some years ago your apportations in these and other forums have been invaluable for me and I'm sure for many others.
Having say that, I'm curious about something. Can Weld be used with TomEE?
Hey BalusC!
Very nice post.
Cannot still use session scoped beans in Tomcat with Weld?
Thanks
This was such a big help to me... thanks BalusC!!!! +1
Thank you. My spring application was running in windows without problem, but not in linux. It was a problem with weld. The log only displayed MalformedParameterizedTypeException and nothing more. After try your tip using weld-servlet-shaded worked like a breeze.
Thanks balusc for all your contribution, this article helped me a lot. But I have an error that I have not been able to solve.
I am using Tomcat 9 and the weld-servlet-shaded dependency and it throws me this error when importing @Postconstruct
The package javax.annotation is accessible from more than one module: , annotations.api
In my Java Build Path I have the tomcat 9 library and in the pom.xml file the dependency weld-servlet-shaded
serve what I add to
BeanManager
javax.enterprise.inject.spi.BeanManager
web.xml
gracias.
Eric Rosas
Thank you so much! I was closely to theow my laptop through the window because my jsf application could run in glassfish but not in tomcat.
Great post but I am rather stuck. I keep getting:
8-Jul-2021 09:31:20.352 INFO [http-nio-8095-exec-9] org.jboss.weld.environment.servlet.EnhancedListener.onStartup WELD-ENV-001008: Initialize Weld using ServletContainerInitializer
08-Jul-2021 09:31:20.409 INFO [http-nio-8095-exec-9] org.jboss.weld.bootstrap.WeldStartup. WELD-000900: 4.0.1 (Final)
08-Jul-2021 09:31:20.560 WARN [http-nio-8095-exec-9] org.jboss.weld.environment.servlet.WeldServletLifecycle.initialize WELD-ENV-000028: Weld initialization skipped - no bean archive found
08-Jul-2021 09:31:20.561 INFO [http-nio-8095-exec-9] org.jboss.weld.environment.servlet.Listener.contextInitialized WELD-ENV-001006: org.jboss.weld.environment.servlet.EnhancedListener used to initialize Weld
08-Jul-2021 09:31:20.621 INFO [http-nio-8095-exec-9] com.sun.faces.config.ConfigureListener.contextInitialized Initializing Mojarra 3.0.1 for context '/test'
08-Jul-2021 09:31:20.729 INFO [http-nio-8095-exec-9] com.sun.faces.spi.InjectionProviderFactory.createInstance JSF1048: PostConstruct/PreDestroy annotations present. ManagedBeans methods marked with these annotations will have said annotations processed.
08-Jul-2021 09:31:21.547 SEVERE [http-nio-8095-exec-9] com.sun.faces.config.ConfigureListener.contextInitialized Critical error during deployment:
jakarta.faces.FacesException: Unable to find CDI BeanManager
using tomcat 10.0.0.8 and Jakarta EE 9
I have carefully put beans.xml in WEB-INF folder
beans xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd" version="3.0"
I have been looking at this for hours! any idea where I might be going wrong?
Thanks a lot, this post allowed me to solve the CDI initialization problem in the jsf application delpoyment on an Apache Tomcat server. Good continuation :).
I really appreciate reading this post. It helped me a lot.
Is there an opportunity to use Tomcat10+ with OpenWebBeans?
Hello @BALUSC,
Great Post We too are migrating our application to myfaces 2.3-next.
We have changed our Managed Beans to CDI (using jboss weld implementation weld-servlet-shaded-3.1.6.Final.jar).
In our application, once we instantiate a request-scoped bean, we encrypt and store them in a String, and for the next consecutive calls we restore beans again from this encrypted String instead of creating it again, by extending ViewHandlerWrapper and writing an implementation in restoreView method (this was done till 2.3.X when beans where managed by MyFaces).
How can we restore a bean in CDI from an encrypted String from 2.3-next? as MyFaces does not Manage the beans anymore, or more precisely which classes can be implemented/extended.
The solution implemented for now:- We have rewritten the class org.jboss.weld.contexts.AbstractContext and integrated implementation in method public T get(Contextual contextual, CreationalContext creationalContext) to restore bean from encrypted String.
org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type CafeRepository with qualifiers @Default
Tomcat Tomcat 10.1.18
Post a Comment