Creating a Custom EL Resolver in JSF
In this tutorial we will create a custom el resolver. We can extend the ELResolver
class to create our own implicit variables in JSF. The following are three simple steps to add custom implicit variables.
- Create a class that extends from the
ELResolver
. - Implement the required abstract methods.
- Register your custom El resolver with the faces-config.xml.
Custom EL Resolver
By extending the ElResolver
class you need to implement 6 methods.
getValue
: this method returns a value if the base isnull
and the property requested is named beers.getType
: this method identifies the type for our property. Determines wheter the call of thesetValue
method is safe without causing aClassCastException
to be thrown.setValue
: this method tries to set the value for a given property and base. If the variable is readonly you’ll need to throw aPropertyNotWritableException
.isReadOnly
: determines wheter a variable is readonly.getFeatureDescriptors
: this method is used by a design time tool. It returns a set of information about the variables or properties that can be resolved.getCommonPropertyType
: returns the most general type that this resolver accepts.
package com.memorynotfound;
import com.sun.faces.util.MessageUtils;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.PropertyNotFoundException;
import javax.el.PropertyNotWritableException;
import java.beans.FeatureDescriptor;
import java.util.Iterator;
public class BeerVarResolver extends ELResolver {
private static final String BEER_PROPERTY_NAME = "beers";
private static final String[] BEERS = new String[]{"La Chouffe", "Stella Artois"};
private final Class<?> CONTENT = String[].class;
@Override
public Object getValue(ELContext ctx, Object base, Object property) {
if ((base == null) && property.equals(BEER_PROPERTY_NAME)){
ctx.setPropertyResolved(true);
return BEERS;
}
return null;
}
@Override
public Class<?> getType(ELContext ctx, Object base, Object property) {
if (base != null){
return null;
}
if (property == null){
String message = MessageUtils.getExceptionMessageString(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property");
throw new PropertyNotFoundException(message);
}
if (property.equals(BEER_PROPERTY_NAME)){
ctx.setPropertyResolved(true);
return CONTENT;
}
return null;
}
@Override
public void setValue(ELContext ctx, Object base, Object property, Object value) {
if (base != null){
return;
}
ctx.setPropertyResolved(false);
if (property == null){
String message = MessageUtils.getExceptionMessageString(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property");
throw new PropertyNotFoundException(message);
}
if (BEER_PROPERTY_NAME.equals(property)){
throw new PropertyNotWritableException((String) property);
}
}
@Override
public boolean isReadOnly(ELContext ctx, Object base, Object property) {
return true;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext ctx, Object base) {
return null;
}
@Override
public Class<?> getCommonPropertyType(ELContext ctx, Object base) {
return String.class;
}
}
Register Custom El Resolver faces-config.xml
To register our custom el resolver with our JSF application, we need to add the following entry to our faces-config.xml file.
<faces-config 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-facesconfig_2_2.xsd" version="2.2">
<application>
<el-resolver>com.memorynotfound.BeerVarResolver</el-resolver>
</application>
</faces-config>
Use Custom EL Resolver
We created our El Resolver and added it to the faces-config.xml. This means we have created an implicit variable that we can use in our JSF pages. We can call the implicit object by #{beers}
shown in the example below.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:body>
<h1>JSF 2.2 Custom El Resolver</h1>
<ul>
<c:forEach var="beer" items="#{beers}">
<li>#{beer}</li>
</c:forEach>
</ul>
</h:body>
</html>
Add FacesServlet to the Servlet Descriptor
<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">
<display-name>JavaServerFaces</display-name>
<!-- Change to "Production" when you are ready to deploy -->
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<!-- Welcome page -->
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
<!-- JSF mapping -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map these files with JSF -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>