Search code examples
jsptagsjstljsp-tags

Does JSP tag libraries work like some kind of tempated JAVA code generation?


(This question is more about how a container includes a tag. And less about how a tag should be implemented. Thanks Ravi Thapliyal for pointing it out.)

I am new to JSP. I learned that JSP pages are finally turned into Servlets.

So I compared the JSP page using some JSTL tags and the servlet Java code generated by the container.

It seems each tag encapsulates a commonly used Java code block with some slots filled/controlled by the tag attributes. And the block is inserted into the _jspService() method.

Is this the general mechanism how tag library contributes to the final servlet Java code?

ADD 1

I dig the generated servlet code for a JSP containing <c:forEach> tag.

The JSP code is this:

Picture 1:

enter image description here

The generated servlet code is this:

Picture 2:

enter image description here

And

Picture 3:

enter image description here

It should be a 2-step process to generate the final response to client:

  1. JSP (picture 1) ==> Servlet Java code (picture 2, 3)
  2. Servlet Java code ==> HTML (Container execute the _jspService() method).

My questions are:

  • Where does the code of picture 2 and 3 come from?

  • And who layout the code of picture 2 and 3 in the servlet class generated from the JSP?

ADD 2

By checking the code in picture 3 and for the org.apache.taglibs.standard.tag.rt.core.ForEachTag class, I guess the ForEachTag type is kind of like an iterator:

  • It is given a collection of items to iterate through.
  • It provides some APIs for external world to control the iteration process.

And to expose the iterated data:

  • It use a scope as a bridge to convey the current iterated item to the external world.

While the outside _jspx_meth_c_005fforEach_005f0 method just use the ForEachTag type to carry out iteration. Until ForEachTag tells him to stop.

So I guess the code in Picture 2 and 3 are just part of the Web Container's JSP parsing logic which are used to support the JSTL tags.

ADD 3

If my analysis about the different responsibility between Web Container and Tab library, how does a container know how to generate code similar to picture 2 and 3 to support a new tag library?

To answer ADD 3

Be it a simple/classic tag, Container only NEEDs to generate boilplate code to invoke their lifecycle methods. Below is an example of a simple tag:

enter image description here

Container only cares about the lifecycle methods. And if there's body, container will further parse the body for the classic tag. For simple tag, the doTag() method covers everything.

ADD 4

After learning the classic tag lifecycle, I understand that org.apache.taglibs.standard.tag.rt.core.ForEachTag is a classic tag handler. The code in picture 3 is the Container invoking the classic lifecycle methods while evaluating the tag body.

The ForEachTag:

  • contains the collection data to loop
  • maintains the loop status
  • and use its lifecycle methods to control the loop.

Solution

  • Yes, your observations are correct. A tag library behaves like a mini templating engine running Java code (as part of the final servlet) with tag attributes (optionally) customizing the Java implementation.

    If you take a look at your JSP file header, that's using any JSTL tags, you'll notice that it imports a tag library descriptor by referencing its URI and assigns it a prefix used later when invoking one of the tags from the library.

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

    The URI is mapped (by the conatiner) to a .tld Tag Library Descriptor file that contains <tag> entries mapping each tag to its implementing Java class and describing all the attributes the tag supports. If you were to implement a custom tag generating an on-screen keyboard, your entry might look like

    <tag>
      <description>Generates an on-screen keyboard</description>
      <name>onScreenKB</name>
      <tag-class>com.myapp.jsp.tags.OnScreenKBTag</tag-class>
      <body-content>empty</body-content>
    </tag>
    

    This .tld file is dropped anywhere under the /WEB-INF directory. The tag handler class needs to implement a specific interface but the container also provides a SimpleTagSupport class that we can extend from.

    public class OnScreenKBTag extends SimpleTagSupport {
    
      public void doTag() throws JspException, IOException {
        StringBuilder html = new StrinBuilder();
        JspWriter out = getJspContext().getOut();
    
        // tag logic
        html.append(...);
        ...
        // print response
        out.print(html);
      }
    }
    

    Then in your JSP file you would import

    <%@ taglib uri="/WEB-INF/tags/myapp.tld" prefix="app" %>
    

    and use your custom tag as

    <div id="keyboard">
      <app:onScreenKB />
    </div>