How to install and use CDI on Tomcat?

I'm creating my first project Java EE 7, but I'm having trouble. Appreciate any help.

  • Tomcat 7.0.34
  • JSF 2.2
  • Primefaces 3.5
  • javaee-api-7.0.jar

When the application start, the Tomcat log shows the following message:

"validateJarFile (C:\...\build\web\WEB-INF\lib\javaee-api-7.0.jar)-jar not loaded. See Servlet 2.3 Spec, section 9.7.2. Offending class: javax/servlet/Servlet .class"

when I click on the button that calls the managed bean, I get the error:

AdvertĂȘncia: /index.xhtml @18,66 value="#{indexMB.user}": Target Unreachable, identifier 'indexMB' resolved to null
javax.el.PropertyNotFoundException: /index.xhtml @18,66 value="#{indexMB.user}": Target Unreachable, identifier 'indexMB' resolved to null

IndexMB

@Named("indexMB")
@RequestScoped
public class IndexMB {

private String password;
private String user;

public String loginTest(){
    return (this.user.equals("admin") ? "adminPage" : "inOutPage");
}

// getters and setters
}

index.xhtml

<html ...>

<f:loadBundle basename="i18n" var="bundle" />
<h:head>
    <title>#{bundle['index_title']}</title>
</h:head>
<h:body>
    #{bundle['index_appname']}
    <br />
    <h:form id="frmIndex">
        <p:panelGrid columns="2">
            <p:outputLabel for="user" value="#{bundle['lblUser']}" />
            <p:inputText id="user" value="#{indexMB.user}" />

            <p:outputLabel for="password" value="#{bundle['lblPassword']}" />
            <p:password id="password" value="#{indexMB.password}" />
        </p:panelGrid>
        <p:commandButton action="#{indexMB.loginTest}" value="#{bundle['btn_login']}" />
    </h:form> 
</h:body>

faces-config.xml

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">

<application>
    <locale-config>
        <default-locale>pt_BR</default-locale>
        <supported-locale>en</supported-locale>
        <supported-locale>fr</supported-locale>
    </locale-config>
</application>

These topics have not helped me:

  • Java EE 6 @javax.annotation.ManagedBean vs. @javax.inject.Named vs. @javax.faces.ManagedBean
  • Target Unreachable identifier resolved to null
  • Target Unreachable, identifier resolved to null
  • javax.el.PropertyNotFoundException : Target Unreachable, identifier 'login' resolved to null Spring + JSF
  • http://www.andrejkoelewijn.com/blog/2010/03/05/jee-cdi-tip-target-unreachable-identifier-resolved-to-null/

Tomcat as being a barebones JSP/Servlet container doesn't support CDI out the box. How exactly did you install CDI? Did you really drop jakartaee-api.jar or javaee-api.jar in /WEB-INF/lib just to get your code to compile? Oh please no, this is not the right way. The JEE API JAR contains solely the API classes, not the concrete implementation. Get rid of the whole JAR. It can cause many other portability troubles like as the ones described in this answer: How do I import the javax.servlet / jakarta.servlet API in my Eclipse project? You should actually be installing the concrete implementation along with the specific API.

You have 2 options:

  1. Drop Tomcat and go for a true Jakarta EE container. As you're using Tomcat, just step over to TomEE. It's really simple, download the TomEE web profile zip file, extract it and integrate it in Eclipse exactly the same way as you did for Tomcat. Don't forget to remove the Jakarta EE JAR file from webapp and alter the Targeted Runtime property in project's properties from Tomcat to TomEE so that Jakarta EE dependencies are properly resolved. See also What exactly is Java EE?

    No additional JARs or configuration is necessary. You can even remove the manually installed JSF/JSTL/CDI/BV/JPA/EJB/JTA/JSONPJAX-RS/etc/etc libraries from your webapp. TomEE as being a true Jakarta EE container already provides them all out the box. In case you're using Maven, the below coordinate is sufficient.

     <dependency>
         <groupId>jakarta.platform</groupId>
         <artifactId>jakarta.jakartaee-web-api</artifactId>
         <version><!-- e.g. 9.0.0 --></version>
         <scope>provided</scope>
     </dependency>
    

    Note the importance of provided and its meaning as in "the target runtime already provides this out the box". See also Tomcat casting servlets to javax.servlet.Servlet instead of jakarta.servlet.http.HttpServlet for detailed pom.xml examples of Tomcat and normal JEE containers.


  2. Install a true CDI implementation on Tomcat. Below instructions assume Tomcat 10+. Weld is one of the available CDI implementations. In the Weld installation guide you can find instructions how to integrate it in Tomcat. For sake of completeness and future reference, here are the steps:

    1. Drop the weld-servlet-shaded.jar in webapp's /WEB-INF/lib. In case you're using Maven, use this coordinate:

       <dependency>
           <groupId>org.jboss.weld.servlet</groupId>
           <artifactId>weld-servlet-shaded</artifactId>
           <version>4.0.0.Final</version>
       </dependency>
      
    2. Create /META-INF/context.xml file in webapp with following content:

       <Context>
           <Resource name="BeanManager" 
               auth="Container"
               type="jakarta.enterprise.inject.spi.BeanManager"
               factory="org.jboss.weld.resources.ManagerObjectFactory"/>
       </Context>
      

      Note that this step is not strictly necessary when you're using Mojarra 2.2.11 or newer as it will be able to find it via ServletContext when absent in JNDI.

    3. Create a /WEB-INF/beans.xml file in webapp. It can be kept empty.

    That's it (note: in older Weld Servlet versions, you'd need to explicitly register the CDI bean manager and Weld listener in web.xml too, but that's unnecessary with current versions).

    In case you prefer OpenWebBeans above Weld as CDI implementation, or need to install CDI in Tomcat 9.x or older, head to this blog for detailed Maven installation instructions: How to install CDI in Tomcat?


Unrelated to the concrete problem, the JSP/Servlet APIs of Tomcat 7 do not comply those APIs of Java EE 7, instead it complies Java EE 6 (Servlet 3.0 / JSP 2.2). If you want the Tomcat equivalent of Java EE 7 (Servlet 3.1 / JSP 2.3), then you should be looking at Tomcat 8. See also Apache Tomcat version matrix.