Programming

How to install JSTL It fails with The absolute uri cannot be resolved or Unable to find taglib or NoClassDefFoundError or ClassCastException

25 September 2026 · 10 min read

How to install JSTL It fails with The absolute uri cannot be resolved or Unable to find taglib or NoClassDefFoundError or ClassCastException

The JavaServer Pages Standard Tag Library (JSTL) is an indispensable tool for developing dynamic web applications with Java. It simplifies JSP development by providing a set of custom tags for common tasks like iteration, conditionals, and XML manipulation, eliminating the need for scriptlets. However, many developers encounter frustrating errors during setup, such as “The absolute uri cannot be resolved,” “Unable to find taglib,” NoClassDefFoundError, or ClassCastException. These issues often stem from incorrect dependency management, misconfigured deployment descriptors, or environment incompatibilities. This guide aims to demystify the process and provide a clear, step-by-step approach on how to install JSTL correctly, ensuring a smooth development experience and troubleshooting the most common pitfalls.

Understanding JSTL and Its Core Components

JSTL stands as a powerful collection of custom tags designed to enhance the readability and maintainability of JavaServer Pages (JSPs). Instead of embedding complex Java code directly into your JSP files, JSTL allows you to use XML-like tags to perform common web development tasks. This separation of concerns—keeping presentation logic distinct from business logic—is a cornerstone of good software engineering practices. By leveraging JSTL, developers can create cleaner, more manageable JSP pages, making collaboration easier and reducing the likelihood of errors.

The library is typically divided into several functional areas, each addressing a specific category of tasks. The “core” library (c:) provides foundational tags for flow control (<c:if>, <c:forEach>) and URL management (<c:url>, <c:redirect>). Other important libraries include the “fmt” (formatting) tags for internationalization and localization, “sql” tags for database access, and “xml” tags for processing XML data. Correctly installing JSTL means ensuring all necessary components are available to your web application, which is crucial for preventing runtime errors like the dreaded NoClassDefFoundError.

According to Apache Tomcat’s official documentation, proper deployment of tag libraries involves ensuring the JAR files are accessible within the web application’s classpath. Without these files, the servlet container cannot resolve the tag URIs, leading directly to “The absolute uri cannot be resolved” or “Unable to find taglib” errors. Understanding this fundamental requirement is the first step toward a successful JSTL setup and avoiding common installation headaches.

Step-by-Step JSTL Installation Guide

Installing JSTL can be approached in a few different ways, depending on your project’s build system. Whether you’re using Maven, Gradle, or setting up dependencies manually, the goal is to get the necessary JSTL JAR files into your web application’s classpath. This section will guide you through the most common methods, helping you understand how to install JSTL efficiently.

Maven/Gradle Setup

For modern Java web projects, using a build automation tool like Maven or Gradle is the most recommended and straightforward method. These tools handle dependency management, ensuring that the correct JSTL libraries are downloaded and included in your project’s WAR file. This approach significantly reduces the chances of encountering issues related to missing classes or version conflicts.

To include JSTL in a Maven project, add the following dependency to your pom.xml file:

<dependency> <groupId>jakarta.servlet.jsp.jstl</groupId> <artifactId>jakarta.servlet.jsp.jstl-api</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>jakarta.servlet.jsp.jstl</artifactId> <version>2.0.0</version> </dependency> 

For Gradle users, add these lines to your build.gradle file:

dependencies { implementation 'jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:2.0.0' implementation 'org.glassfish.web:jakarta.servlet.jsp.jstl:2.0.0' } 

After adding these dependencies, perform a Maven clean install (mvn clean install) or Gradle build (gradle build) to download and package the JSTL JARs. This process automatically places the required .jar files into your web application’s WEB-INF/lib directory when the WAR is built, resolving many classpath-related issues.

Manual Installation

If you are not using a build tool or prefer manual control, you will need to download the JSTL JAR files directly and place them into your web application’s deployment directory. This method requires careful attention to detail to avoid common errors.

  1. Download JSTL JARs: Obtain the necessary JSTL JAR files (e.g., jakarta.servlet.jsp.jstl-api-2.0.0.jar and jakarta.servlet.jsp.jstl-2.0.0.jar) from a reputable repository like Maven Central.
  2. Locate WEB-INF/lib: In your web application’s directory structure, navigate to WEB-INF/lib. If this directory doesn’t exist, create it.
  3. Place JARs: Copy the downloaded JSTL JAR files into the WEB-INF/lib directory.
  4. Restart Server: After placing the JARs, restart your servlet container (e.g., Apache Tomcat) to ensure it picks up the new libraries.

Once the JARs are in place, you can use JSTL tags in your JSPs. Remember to declare the tag library at the top of your JSP file. For example, for the core JSTL tags, you would add:

<%@ taglib uri="jakarta.tags.core" prefix="c" %> 

Using the correct URI is paramount. Older versions of JSTL (pre-2.0, part of Java EE) used URIs like http://java.sun.com/jsp/jstl/core, while newer versions (part of Jakarta EE) use jakarta.tags.core. Mismatching these URIs with your installed JSTL version is a common cause of “Unable to find taglib” errors.

Troubleshooting Common JSTL Installation Errors

Even with careful installation, developers frequently encounter errors that prevent JSTL from functioning correctly. Understanding these common issues and their resolutions is key to efficiently debugging your web applications. Here’s how to tackle the most prevalent problems when trying to install JSTL.

“The absolute uri cannot be resolved” or “Unable to find taglib”

These messages are perhaps the most common JSTL installation errors. They indicate that your servlet container cannot locate the definition for the tag library you are trying to use. This typically boils down to one of two reasons: either the JSTL JAR files are not in the web application’s classpath, or the URI specified in your <%@ taglib %> directive does not match the URI defined within the JSTL TLD (Tag Library Descriptor) files.

  • Check WEB-INF/lib: Verify that the JSTL JAR files (e.g., jakarta.servlet.jsp.jstl-api.jar and jakarta.servlet.jsp.jstl.jar for JSTL 2.0+) are present in your web application’s WEB-INF/lib directory. If they are missing, your application server simply cannot find the necessary classes.

  • Correct Taglib URI: Ensure your <%@ taglib %>Question & Answer :
    I don’t know what I’ve done incorrectly, but I can’t include JSTL. I have jstl-1.2.jar, but unfortunately I get exception:

    org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application

    I have this in pom.xml:

    <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> 
    

    I’m trying to use it as follows:

    <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> 
    

    In your specific case,

    org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application

    that URI is for JSTL 1.0, but you’re actually using JSTL 1.2 which uses URIs with an additional /jsp path. This URI change is because JSTL, who invented EL expressions, was since version 1.1 integrated as part of JSP 2.0 (released way back in 2001!) in order to share/reuse the EL logic in plain JSP too. See also Difference between JSP EL, JSF EL and Unified EL.

    So, fix the taglib URI accordingly based on JSTL 1.2 documentation:

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
    

    Further you need to make absolutely sure that you do not throw multiple different versioned JSTL JAR files together into the runtime classpath or versions which don’t match the expected version by the target runtime (the server) or merely the API without impl. Otherwise you risk seeing other errors like below:

    org.apache.jasper.JasperException: Can not find the tag library descriptor for “http://java.sun.com/jsp/jstl/core"

    org.apache.jasper.JasperException: Unable to find taglib [c] for URI: [jakarta.tags.core]

    java.lang.NoClassDefFoundError: javax/servlet/jsp/tagext/TagLibraryValidator

    java.lang.NoClassDefFoundError: jakarta/servlet/jsp/tagext/TagLibraryValidator

    java.lang.ClassCastException: class org.apache.taglibs.standard.tlv.JstlCoreTLV cannot be cast to class jakarta.servlet.jsp.tagext.TagLibraryValidator

    This is a pretty common mistake among Tomcat users. The problem with Tomcat is that it does not offer JSTL out the box and thus you have to manually install it. This is not necessary in normal Jakarta EE servers. See also What exactly is Java EE? and How to properly configure Jakarta EE libraries in Maven pom.xml for Tomcat?

    In your specific case, your pom.xml basically tells you that you have jstl-1.2.jar and standard-1.1.2.jar together. This is wrong. You’re basically mixing JSTL 1.2 API+impl from Oracle (GlassFish) with JSTL 1.1 impl from Apache. You should remove duplicate JSTL implementations and stick to only one JSTL implementation and the API version must match the impl version and the API version must be supported by the target runtime.

    Installing JSTL on Tomcat 10.1.x

    In case you’re already on Tomcat 10.1.x (the second Jakartified version, with jakarta.* package instead of javax.* package, but the first version with the updated jakarta.tags.* namespace URNs instead of http://java.sun.com/jsp/jstl/* namespace URLs), use JSTL 3.0 via these dependency using the default Maven scope of compile (because Tomcat doesn’t provide it out the box!):

    <dependency> <groupId>jakarta.servlet.jsp.jstl</groupId> <artifactId>jakarta.servlet.jsp.jstl-api</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>jakarta.servlet.jsp.jstl</artifactId> <version>3.0.1</version> </dependency> 
    

    Note that the API dependency is since this version not transitively included via the impl dependency, so you do need to explicitly declare it.

    Non-Maven users can achieve the same by dropping the following two physical files in /WEB-INF/lib folder of the web application project (do absolutely not drop standard*.jar or any loose .tld files in there! remove them if necessary).

    As said, the namespace URIs have been changed to become URNs instead of URLs. JSTL core is since JSTL version 3.0 available via an easier to remember namespace URI in URN format:

    <%@ taglib prefix="c" uri="jakarta.tags.core" %> 
    

    See also JSTL 3.0 documentation.

    In case you actually wanted to use the JSTL impl of Apache instead of EE4J then you need to know that they don’t have a 3.0 let alone 2.0. The currently latest released version of Apache’s JSTL impl is 1.2.3 and it is not anymore actively maintained since Feb 2015. The JSTL impl from EE4J (formerly Oracle / Sun) is currently (Jul 2023) your only choice.

    Installing JSTL on Tomcat 10.0.x

    In case you’re on Tomcat 10.0.x (the first Jakartified version, with jakarta.* package instead of javax.* package), use JSTL 2.0 via this sole dependency using the default Maven scope of compile (because Tomcat doesn’t provide it out the box!):

    <dependency> <groupId>org.glassfish.web</groupId> <artifactId>jakarta.servlet.jsp.jstl</artifactId> <version>2.0.0</version> </dependency> 
    

    Note that the API dependency is already transitively included via this impl dependency, so you do not need to explicitly declare it.

    Non-Maven users can achieve the same by dropping the following two physical files in /WEB-INF/lib folder of the web application project (do absolutely not drop standard*.jar or any loose .tld files in there! remove them if necessary).

    Installing JSTL on Tomcat 9-

    In case you’re not on Tomcat 10 yet, but still on Tomcat 9 or older, use JSTL 1.2 via this sole dependency (this is compatible with Tomcat 9 / 8 / 7 / 6 / 5 but not older) using the default Maven scope of compile (because Tomcat doesn’t provide it out the box!):

    <dependency> <groupId>org.glassfish.web</groupId> <artifactId>jakarta.servlet.jsp.jstl</artifactId> <version>1.2.6</version> </dependency> 
    

    Note that the API dependency is already transitively included via this impl dependency, so you do not need to explicitly declare it.

    Non-Maven users can achieve the same by dropping the following two physical files in /WEB-INF/lib folder of the web application project (do absolutely not drop standard*.jar or any loose .tld files in there! remove them if necessary).

    Installing JSTL on normal JEE server

    In case you’re actually using a normal Jakarta EE server such as WildFly, Payara, TomEE, GlassFish, WebSphere, OpenLiberty, WebLogic, etc instead of a barebones servletcontainer such as Tomcat, Jetty, Undertow, etc, then you do not need to explicitly install JSTL at all. Normal Jakarta EE servers already provide JSTL out the box. In other words, you don’t need to add JSTL to pom.xml nor to drop any JAR/TLD files in webapp. Solely the provided scoped Jakarta EE coordinate is sufficient:

    <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-api</artifactId> <version><!-- 10.0.0, 9.1.0, 9.0.0, 8.0.0, etc depending on your server --></version> <scope>provided</scope> </dependency> 
    

    Make sure web.xml version is right

    Further you should also make sure that your web.xml is declared conform at least Servlet 2.4 and thus not as Servlet 2.3 or older. Otherwise EL expressions inside JSTL tags would in turn fail to work. Pick the highest version matching your target container and make sure that you don’t have a <!DOCTYPE> anywhere in your web.xml as that would otherwise still trigger Servlet 2.3 modus. Here’s a Servlet 6.0 (Tomcat 10.1.x) compatible example:

    <?xml version="1.0" encoding="UTF-8"?> <web-app 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/web-app_6_0.xsd" version="6.0"> <!-- Config here. --> </web-app> 
    

    And here’s a Servlet 5.0 (Tomcat 10.0.x) compatible example:

    <?xml version="1.0" encoding="UTF-8"?> <web-app 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/web-app_5_0.xsd" version="5.0"> <!-- Config here. --> </web-app> 
    

    And here’s a Servlet 4.0 (Tomcat 9) compatible example:

    <?xml version="1.0" encoding="UTF-8"?> <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_4_0.xsd" version="4.0"> <!-- Config here. --> </web-app> 
    

    See also: