Introduce JSF EL implicit variables by custom EL resolver
November 10, 2011 13:19:13 Last update: December 01, 2011 19:10:43
You can add custom implicit variables to JSF pages by using a custom EL resolver, in two simple steps:
Starting from the Maven Hello World example:
Fixed: the
When values need to be set on a managed bean, throwing exception here stops further processing and causes the whole page to fail, even when the introduced variable is not used.
- Write an
ELResolverclass to resolve the variable - Add the
ELResolvertofaces-config.xml
Starting from the Maven Hello World example:
- Add faces API and EL dependencies to
pom.xml:<dependencies> <dependency> <groupId>org.apache.myfaces.core</groupId> <artifactId>myfaces-api</artifactId> <version>2.1.3</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>2.2.3</version> <scope>provided</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies>
- Add a simple greeter class (
src/main/java/com/example/Greeter.java):package com.example; public class Greeter { public String sayHi(String name) { return "Hello " + name + "!"; } }
- Add our custom EL resolver (
src/main/java/com/example/ELResolver.java):package com.example; import java.util.Iterator; import java.beans.FeatureDescriptor; import javax.el.ELContext; import javax.el.PropertyNotWritableException; /** * This class introduces an implicit variable 'Greeter' into the EL space. * It does variable resolution only, property resolution is left to the built-in * resolvers. For variable resolution, base is always null, property is String. */ public class ELResolver extends javax.el.ELResolver { private static final String GREETER = "Greeter"; @Override public Class<?> getCommonPropertyType(ELContext ctx, Object base) { return null; } @Override public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext ctx, Object base) { return null; } @Override public Class<?> getType(ELContext ctx, Object base, Object property) { if ((base == null) && property.equals(GREETER)) { ctx.setPropertyResolved(true); return Greeter.class; } return null; } @Override public Object getValue(ELContext ctx, Object base, Object property) { if ((base == null) && property.equals(GREETER)) { ctx.setPropertyResolved(true); return new Greeter(); } return null; } @Override public boolean isReadOnly(ELContext ctx, Object base, Object property) { return true; } @Override public void setValue(ELContext ctx, Object base, Object property, Object value) { ctx.setPropertyResolved(false); } }
- Add the custom EL resolver to
src/main/resources/META-INF/faces-config.xml<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_1.xsd" version="2.1"> <application> <el-resolver>com.example.ELResolver</el-resolver> </application> </faces-config>
- Build JAR with
mvn package
- Drop the JAR into
WEB-INF/libof a webapp and test the new EL with:<h:outputText value="#{Greeter.sayHi('Mike')}"/>
Fixed: the
setValue method used to throw an exception, which is wrong.
@Override public void setValue(ELContext ctx, Object base, Object property, Object value) { // This is WRONG! throw new PropertyNotWritableException("I don't set value"); }
When values need to be set on a managed bean, throwing exception here stops further processing and causes the whole page to fail, even when the introduced variable is not used.