Using JSTL in JSF?

Lets see!

So just another usual day, me minding my own business with the following code..

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/maven-v4_0_0.xsd">
 
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>biz.tugay</groupId>
    <artifactId>jsfbootstrap</artifactId>
    <packaging>war</packaging>
 
    <version>1.0-SNAPSHOT</version>
 
    <name>jsfbootstrap Maven Webapp</name>
    <url>http://www.tugay.biz</url>
 
    <dependencies>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.2.13</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.2.13</version>
        </dependency>
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>3.0.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>jsfbootstrap</finalName>
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.2.1.v20140609</version>
            </plugin>
        </plugins>
    </build>
 
</project>

web.xml
<web-app 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-app_3_1.xsd"
         version="3.1">
 
    <servlet>
        <servlet-name>FacesServlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>FacesServlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
 
    <welcome-file-list>
        <welcome-file>bar.xhtml</welcome-file>
    </welcome-file-list>
 
</web-app>

StudentBean.java
package biz.tugay;
 
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import java.util.ArrayList;
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 7/23/2016
 * Time: 5:32 PM
 */
 
@ManagedBean
@SessionScoped
public class StudentBean {
 
    final private List<Student> studentList = new ArrayList<Student>();
 
    {
        final Student korayTugay = new Student();
        korayTugay.setFullname("Koray Tugay");
        studentList.add(korayTugay);
 
        final Student mickJagger = new Student();
        mickJagger.setFullname("Mick Jagger");
        studentList.add(mickJagger);
    }
 
    public List<Student> getStudentList() {
        return studentList;
    }
}

bar.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<h:head>
    <title>Student List</title>
</h:head>
<h:body>
    <c:forEach items="#{studentBean.studentList}"
               var="student">
        #{student.fullname}
        <br/>
    </c:forEach>
</h:body>
</html>

So as usual I will just build this project and fire up jetty:
mvn clean install
mvn jetty:start
and everything will be fine..

This is what I see on my browser:

And I do not really expect anything else so all is fine.. Now for some reason I decide to deploy the war to to Tomcat 8.5.4..

And what do I get?

So the journey begins..

Please check this Stackoverflow post first. So it seems like we need this LoopTagStatus interface in our classpath. So I added one myself. I created a package in my project: javax.servlet.jsp.jstl.core and just added this Interface as seen below:
package javax.servlet.jsp.jstl.core;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 7/23/2016
 * Time: 7:46 PM
 */
public interface LoopTagStatus {
 
 
    /**
     * Retrieves the current item in the iteration.  Behaves
     * idempotently; calling getCurrent() repeatedly should return the same
     * Object until the iteration is advanced.  (Specifically, calling
     * getCurrent() does <b>not</b> advance the iteration.)
     *
     * @return the current item as an object
     */
    public Object getCurrent();
 
    /**
     * Retrieves the index of the current round of the iteration.  If
     * iteration is being performed over a subset of an underlying
     * array, java.lang.Collection, or other type, the index returned
     * is absolute with respect to the underlying collection.  Indices
     * are 0-based.
     *
     * @return the 0-based index of the current round of the iteration
     */
    public int getIndex();
 
    /**
     * <p>Retrieves the "count" of the current round of the iteration.  The
     * count is a relative, 1-based sequence number identifying the
     * current "round" of iteration (in context with all rounds the
     * current iteration will perform).</p>
     *
     * <p>As an example, an iteration with begin = 5, end = 15, and step =
     * 5 produces the counts 1, 2, and 3 in that order.</p>
     *
     * @return the 1-based count of the current round of the iteration
     */
    public int getCount();
 
    /**
     * Returns information about whether the current round of the
     * iteration is the first one.  This current round may be the 'first'
     * even when getIndex() != 0, for 'index' refers to the absolute
     * index of the current 'item' in the context of its underlying
     * collection.  It is always that case that a true result from
     * isFirst() implies getCount() == 1.
     *
     * @return <tt>true</tt> if the current round is the first in the
     * iteration, <tt>false</tt> otherwise.
     */
    public boolean isFirst();
 
    /**
     * Returns information about whether the current round of the
     * iteration is the last one.  As with isFirst(), subsetting is
     * taken into account.  isLast() doesn't necessarily refer to the
     * status of the underlying Iterator; it refers to whether or not
     * the current round will be the final round of iteration for the
     * tag associated with this LoopTagStatussss.
     *
     * @return <tt>true</tt> if the current round is the last in the
     * iteration, <tt>false</tt> otherwise.
     */
    public boolean isLast();
 
    /**
     * Returns the value of the 'begin' attribute for the associated tag,
     * or null if no 'begin' attribute was specified.
     *
     * @return the 'begin' value for the associated tag, or null
     * if no 'begin' attribute was specified
     */
    public Integer getBegin();
 
    /**
     * Returns the value of the 'end' attribute for the associated tag,
     * or null if no 'end' attribute was specified.
     *
     * @return the 'end' value for the associated tag, or null
     * if no 'end' attribute was specified
     */
    public Integer getEnd();
 
    /**
     * Returns the value of the 'step' attribute for the associated tag,
     * or null if no 'step' attribute was specified.
     *
     * @return the 'step' value for the associated tag, or null
     * if no 'step' attribute was specified
     */
    public Integer getStep();
 
}

And you know what? Tomcat was happy! The loop worked! But this is not the way to go, this is a hack. So I said you know I will just add the following dependency in pom.xml:
<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

Well, yes, Tomcat was happy again. BUT! Lets check the Maven repository page to see what is going on for this dependency:
Note: This artifact was moved to:
 
New Group javax.servlet.jsp.jstl
New Artifact jstl-api

Ah, ok.. Lets DO NOT use this..

How about the following dependency?
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency

Well, we still have this message on the Maven page:
Note: This artifact was moved to:
 
New Group javax.servlet.jsp.jstl
New Artifact jstl-api
however, on top of that, jstl tag page in Stackoverflow states that:
This is by the way the JSTL API bundled with Apache's JSTL implementation in a single JAR flavor. This does not require the standard.jar (it's for JSTL 1.1 only). Note that there's also a jstl:jstl dependency, but it's exactly the same file, only with a wrong group ID.
The problem is, we already have the implementation, again quoting from the same page:
Facelets, the successor of JSP, has among the provided taglibs a selected subset of JSTL 1.2 core and the full set of JSTL 1.2 functions builtin.
But we still need the API dependency. So we finally pick just the API and not the implementation from maven:
<dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>javax.servlet.jsp.jstl-api</artifactId>
    <version>1.2.1</version>
</dependency>
.. and Tomcat is happy! This dependency will have the required Interface, just fine!

Lets add some notes:
  • The real JSTL 1.0 taglib uses the URI http://java.sun.com/jstl/core.
  • The real JSTL 1.1/1.2 taglib uses the URI http://java.sun.com/jsp/jstl/core.
  • Facelets 1.x uses the URI http://java.sun.com/jstl/core.
  • Facelets 2.x uses the URI http://java.sun.com/jsp/jstl/core.
  • Facelets 2.2+ uses the URI http://xmlns.jcp.org/jsp/jstl/core.
  • Facelets don't ship with the full tag set as the real JSTL taglib. Only a few of the <c:xxx> and the full set of <fn:xxx> are copied into Facelets.
http://stackoverflow.com/tags/jstl/info
http://stackoverflow.com/questions/7593603/jstl-xmlns-namespace-differences-between-jsf-1-2-and-jsf-2-x
http://stackoverflow.com/questions/3342984/jstl-in-jsf2-facelets-makes-sense