Run REST APIs with JSP.
We all love JSP because its simple. It helps us easily modify the server response, without recompilation and re-deployment. But there is no easy way of handling API requests in JSP.
JSP is a view technology, it is used to display server response. API requests are handled by the servlet and forwarded to JSP for API response.
But wait thats what we don't want.
If the servlet handles API requests, changing the Java code wouldn't be as easy as changing the JSP.
Does that mean we move our Java code to scriplets in JSP. A lot of developers around the world have done that over last decade. Balusc keeps telling everyone not to do scriplets. And all those who do scriptlets in JSP, have a lot of unmaintainable code. How to avoid Java code in JSP
I'm not saying they don't work but jsp scriptlets get messy and they won't give you a good stack trace when handling errors.
It is hand to identify the line number of the error if written in scriplets.
Disadvantages of scriplets
We want a mechanism that allows us to
The answer is Tag Libraries
JSTL provides a good number of tags for formatting, SQL operations, functions, and logical operations. Maintaining a JSP with tag libraries and JSTL is easier than maintaining java code. Using JSTL to Enhance JSP Functionality. JSP custom tag development allows organizing commonly used operations into tags. This helps us to maintain domain-specific tags and reuse them across the JSP pages.
Here the domain is REST APIs so we need a set of rest specific tag library
Mason is a jsp tag library that provides a set of tags to handle API requests. Mason is just a tag library. It can work with your existing webapp.
What does mason provide
<jsp:directive.page pageEncoding="UTF-8" trimDirectiveWhitespaces="true"/>
<%@taglib uri="mtg-mason.tld" prefix="m" %>
<m:resource>
<m:request method="GET">
<m:execute className="com.example.RequestHandler" var="getCustomer"
param="${mtgReq}" output="true"/>
</m:request>
</m:resource>
If you save this file with customer.jsp
, you can access it at
http://localhost:8080/rest/v1.0/customer
You don't need to add the .jsp
extension in the url.
Mason provides an execute
tag to invoke code. You can return any JAXB compliant object from the class
and it will be converted to json/xml depending on the Accept
header
package com.example;
import com.metamug.entity.Request;
import com.metamug.entity.Response;
import com.metamug.exec.RequestProcessable;
import com.example.entity.Customer;
import java.util.Map;
import javax.sql.DataSource;
/**
*
* @author anishhirlekar
*/
public class RequestHandler implements RequestProcessable {
@Override
public Response process(Request request, DataSource ds, Map<String, Object> args) throws Exception {
Customer customer = new Customer();
customer.setName("John Doe.");
customer.setId(8);
customer.setContact("+1 943 322 4292", "john.doe@gmail.com");
Response response = new Response();
// set your model object as payload here
response.setPayload(customer);
return response;
}
}
You need to add the following dependency to your pom.xml
to run mason tag library.
<dependency>
<groupId>com.metamug</groupId>
<artifactId>mason</artifactId>
<version>3.3</version>
</dependency>
If your project isn't a maven project, you can add mason jar from github releases to your lib folder. There is a mason sample project with all the jar libraries.
Add the mason filter in the web.xml so that it can handle the API requests coming to the jsp
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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">
<filter>
<filter-name>Router</filter-name>
<filter-class>com.metamug.mason.Router</filter-class>
</filter>
<filter-mapping>
<filter-name>Router</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
</web-app>
We have added a github maven project that demonstrates the above code.