Deploying a JSF 2.3 Application on Tomcat 9

1 Comment
Java EE Servlet

It’s exciting to work with the latest technologies, and it’s exciting to try to set things up because eventually, it helps you learn. This is how I ran a JSF 2.3 application on a Tomcat 9.

Before getting started, you may say that this is a simple task, it is, it’s not a big deal, but I decided to write this for 2 reasons, first to simply keep a history of what I did, second the highlight some things that I have encountered along the way.

So I started by preparing my environment, I am working on a Windows 10, so I downloaded and extracted my favorite IDE, Eclipse.

The version that I used was the latest Oxygen build:

Version: Oxygen.1a Release (4.7.1a)
Build id: 20171005-1200

I configured Eclipse to use JDK 1.8, specifically jdk1.8.0_152.

I began by creating a new Maven project with no archetype. And so the hunt for dependencies begins.

I chose Tomcat 9 because I am familiar with it although Tomcat is not a full Java EE container and so it doesn’t contain JSF, JPA and so on… There is TomEE but the latest version that I found supports Java EE 7, and I’m interested in working on Java EE 8, that means Servlet 4.0 and HTTP 2.0!

So preparing now the POM file, I fetched my first 2 dependencies:

 

 <!-- Servlet -->
 <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.0</version>
    <scope>provided</scope>
 </dependency>
 <!-- JSF API -->
 <dependency>
    <groupId>javax.faces</groupId>
    <artifactId>javax.faces-api</artifactId>
    <version>2.3</version>
 </dependency>

These were enough to allow me to set up a ServletContextListener in order to register the JSF Servlet famously known as FacesServlet, so I created the following class:

 

package web.tier.listeners;
 
import java.util.logging.Logger;
 
import javax.faces.webapp.FacesServlet;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRegistration.Dynamic;
import javax.servlet.annotation.WebListener;
 
@WebListener
public class MyServletContextListener implements ServletContextListener {
   @Override
   public void contextInitialized(ServletContextEvent sce) {
      ServletContextListener.super.contextInitialized(sce);
 
      //Registering the JSF Servlet
      Dynamic facesServlet = sce.getServletContext().addServlet("FacesServlet", FacesServlet.class);
      //Specifying the Servlet Mapping
      facesServlet.addMapping("*.xhtml");
      //Setting Priority, 0 or higher for eager, if negative then it's lazy
      facesServlet.setLoadOnStartup(1);
 
      Logger.getGlobal().info("Servlet Context has been initialized");
   }
}

So I started my app on Tomcat without any web.xml or faces-config.xml and I received a NullPointerException when I try to add the Servlet. According to the java doc of addServlet this will return a null in case this Servlet is already registered. Nice! It seems Faces Servlet was already registered. I validated this by retrieving the Servlet Registrations from the Servlet Context. It also defines mappings such as *.xhtml. Cool! By the way, I tested GlassFish 5 and I couldn’t detect the same behavior.

So simply I removed those 3 lines from my class, and ran my application again, this time, I received that some class is not found, something related to JSF, and I remembered that I am using Tomcat, so I also need an implementation for JSF! So I added the Mojarra dependency:

 

<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.faces</artifactId>
   <version>2.3.0</version>
</dependency>

And I remembred that I haven’t created yet any bean or page, so I created a very simple xhtml page with a very simple bean, and yes we need to use CDI annotations, so I added the following dependencies to my POM. (As you can see I’m always after the latest specs of Java EE 8)

 

<dependency>
   <groupId>javax.enterprise</groupId>
   <artifactId>cdi-api</artifactId>
   <version>2.0</version>
</dependecy>

And now I started the application again, please note that this is the first time I work with CDI, previously I used @ManagedBean and Spring. So I got an exception, and I need to write it down…

 

Caused by: javax.faces.FacesException: Unable to find CDI BeanManager
 at com.sun.faces.el.ELUtils.buildFacesResolver(ELUtils.java:259)
 at com.sun.faces.application.ApplicationAssociate.initializeELResolverChains(ApplicationAssociate.java:473)
 at com.sun.faces.application.ApplicationImpl.performOneTimeELInitialization(ApplicationImpl.java:1369)
 at com.sun.faces.application.ApplicationImpl.getELResolver(ApplicationImpl.java:491)
 at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:256)
 ... 30 more

So I went to see what’s happening inside the class ELUtils and I saw a very strange line, which basically says, if you’re using JSF 2.3 or Servlet 4.0, then throw an exception! And I was like… WHAT THE ****!

 

if (beanManager == null) {
    // TODO: use version enum and &gt;=
   if (getFacesConfigXmlVersion(facesContext).equals("2.3") || getWebXmlVersion(facesContext).equals("4.0")) {
       throw new FacesException("Unable to find CDI BeanManager");
   }
} else {
   CdiExtension cdiExtension = getBeanReference(beanManager, CdiExtension.class);
   if (cdiExtension.isAddBeansForJSFImplicitObjects()) {
       composite.add(beanManager.getELResolver());
       return true;
   }
}

And so I almost arrived at a conclusion that says that I am using now Mojarra 2.3 and it’s going to throw an Exception whenever it detects Servlet 4.0, I was down, sad, until I saw that there’s a new version on Maven, and it’s 2.3.0-m05.

I changed the version in my POM but I also got the same error, this time, the source code was changed, now it tries to detect a BeanManager from the FacesContext, I didn’t know what that means (I am new to CDI!) but finally at least something to try to solve.

BalusC always comes to the rescue, he has a post on how to fix the CDI thing on Tomcat. I learned that yeah, I need an implementation for CDI, there’s one called Weld and what made me happy more is that I saw that BalusC updated this post a few days ago only. So I followed his tips and I added the implementation dependency in my POM as well as an empty beans.xml file.

Finally, it was solved 😀

One Reply to “Deploying a JSF 2.3 Application on Tomcat 9”

  1. Thanks for the write up i did the same with tomcat 8 using weld yet am get error messsage unsatisfied dependency: no bean matches the injection point. How will i be able to fix this

Leave a Reply

%d bloggers like this: