Chapter 9: Import constants, interfaces, enums and public static methods
There is a common practice for declaring constants using the public static final declaration:
public class SpinnerBean {
public static final int MIN = 10;
public static final int MAX = 100;
public static final int[] MINMAXARRAY = {MIN, MAX};
public static final Set<Integer> MINMAXSET = Utils.unmodifiableSet(MIN, MAX);
}
Also, Java interfaces and enums are very useful in applications (they are part of the Java language “bricks”):
public interface ATP {
public String website = "http://www.atpworldtour.com/";
}
public enum PlayerEnum {
R_NADAL, R_FEDERER, D_FERER;
public Integer getRank() {
switch (name()) {
case "R_NADAL":
return 1;
case "R_FEDERER":
return 2;
case "D_FERER":
return 3;
default:
return 0;
}
}
}
Now, when we write helper methods (public static methods with a non void return type), we usually group them in final classes as below:
public final class PlayerHelper implements Serializable {
private static final long serialVersionUID = 1L;
public static boolean isPlayerAvailable(int rank) {
// look for player, or at least do something else
Random rnd = new Random();
if (rnd.nextInt(10) < 5) {
return false;
}
return true;
}
}
Now, let’s suppose that we have these artifacts in a JSF application, as a JSF page author we need to use them in page via EL, as below:
// use constants
#{SpinnerBean.MIN}
#{SpinnerBean.MAX}
// use interfaces and enums
#{ATP.website}
#{PlayerEnum.R_NADAL}
// use public static non void methods
#{PlayerHelper:isPlayerAvailable(1)}
There is no elegant way to say that the above usages will simply not work! Of course, we can wrap the constants and enums in bean properties/methods and the helper methods in custom Facelets taglib functions, but this is not our purpose.
Import constants/interfaces via PrimeFaces and OmniFaces
In order to import constants, we can use the PrimeFaces approach. Actually, we are talking about PrimeFaces Extensions. As you probably know, PrimeFaces Extensions are built on top of PrimeFaces and consists of a lightweight open source component library for Java Server Faces 2.0. In order to use it, you need to add the specific dependency (or JAR) in your project. One of the utilities provided by PrimeFaces Extensions is dedicated for exposing constants in EL expressions. The tag is named <pe:importConstants/> and it supports two important attributes. The constants can be accessed via the name of the class (default setting) indicated via the required className attribute, or via a custom name indicated via the optional var attribute. For example, we can expose in EL the constants from SpinnerBean class as below:
// expose class constants in EL
<pe:importConstants className="beans.SpinnerBean" />
<pe:importConstants className="beans.SpinnerBean" var="MINMAX_PF" />
// usage examples
<p:spinner min="#{SpinnerBean.MIN}" max="#{SpinnerBean.MAX}" />
<p:spinner min="#{MINMAX_PF.MIN}" max="#{MINMAX_PF.MAX}" />
<p:spinner min="#{SpinnerBean.MINMAXARRAY[0]}"
max="#{SpinnerBean.MINMAXARRAY[1]}" />
<p:spinner min="#{MINMAX_PF.MINMAXARRAY[0]}"
max="#{MINMAX_PF.MINMAXARRAY[1]}" />
<p:spinner min="#{SpinnerBean.MINMAXSET.toArray()[1]}"
max="#{SpinnerBean.MINMAXSET.toArray()[0]}" />
<p:spinner min="#{MINMAX_PF.MINMAXSET.toArray()[1]}"
max="#{MINMAX_PF.MINMAXSET.toArray()[0]}" />
For an interface we have something like this:
// expose interface constants in EL
<pe:importConstants className="beans.ATP" />
<pe:importConstants className="beans.ATP" var="atp" />
// usage examples
<h:outputLink id="atppfId" value="#{atp.website}">ATP WEBSITE</h:outputLink>
<p:tooltip for="atppfId" value="#{atp.website}" />
<p:tooltip for="atppfId" value="#{ATP.website}" />
On the other hand, OmniFaces comes with a tag handler named, <o:importConstants/> that is capable of mapping all constant field values of a given fully qualified name of type in the request scope. The constants can be accessed via EL; once we import them as below (the type attribute is required and its value represents the fully qualified name of the class/interface/enum to import and the constant field values for). The <o:importConstants/> also supports the var attribute. You can use it to indicate an alias (the name of the request attribute which exposes the mapping of the constants in the request scope):
// expose class constants in EL
<o:importConstants type="beans.SpinnerBean" />
<o:importConstants type="beans.SpinnerBean" var="MINMAX_OF" />
// usage examples
<p:spinner min="#{SpinnerBean.MIN}" max="#{SpinnerBean.MAX}" />
<p:spinner min="#{MINMAX_OF.MIN}" max="#{MINMAX_OF.MAX}" />
<p:spinner min="#{SpinnerBean.MINMAXARRAY[0]}"
max="#{SpinnerBean.MINMAXARRAY[1]}" />
<p:spinner min="#{MINMAX_OF.MINMAXARRAY[0]}"
max="#{MINMAX_OF.MINMAXARRAY[1]}" />
<p:spinner min="#{SpinnerBean.MINMAXSET.toArray()[1]}"
max="#{SpinnerBean.MINMAXSET.toArray()[0]}" />
<p:spinner min="#{MINMAX_OF.MINMAXSET.toArray()[1]}"
max="#{MINMAX_OF.MINMAXSET.toArray()[0]}" />
For an interface we have something like this:
// expose interface constants in EL
<o:importConstants type="beans.ATP" />
<o:importConstants type="beans.ATP" var="atp" />
// usage examples
<h:outputLink id="atppfId" value="#{atp.website}">ATP WEBSITE</h:outputLink>
<p:tooltip for="atppfId" value="#{atp.website}" />
<p:tooltip for="atppfId" value="#{ATP.website}" />
The complete application is named, PFOFImportConstants.
Import enums via PrimeFaces and OmniFaces
Further let’s focus on importing the PlayerEnum enum. Again, let’s start with PrimeFaces Extensions approach. This time we will focus on the tag named <pe:importEnum/> and its two important supporting attributes. The enums can be accessed via the name of the class (default setting) indicated via the required type attribute, or via a custom name indicated via the optional var attribute. It is also possible to get all enum values of the class with the ALL_VALUES suffix or a custom prefix via the allSuffix attribute. For example, we can expose in EL the PlayerEnum like below:
// expose enum in EL
<pe:importEnum type="beans.PlayerEnum" allSuffix="ALL_ENUM_VALUES" />
<pe:importEnum type="beans.PlayerEnum" var="enumpf"
allSuffix="ALL_ENUM_VALUES" />
// Loop enum values:
<ui:repeat value="#{enumpf | PlayerEnum.ALL_ENUM_VALUES}" var="t">
#{t}
</ui:repeat>
// Providing enum values as dropdown items and test R_NADAL item:
<h:form>
<p:selectOneMenu value="#{playerBean.selectedPlayerEnum}">
<f:selectItems value="#{enumpf | PlayerEnum.ALL_ENUM_VALUES}" />
<p:ajax update="@form" />
</p:selectOneMenu>
#{playerBean.selectedPlayerEnum}
[#{playerBean.selectedPlayerEnum == enumpf | PlayerEnum.R_NADAL}]
</h:form>
// Providing enum values as dropdown items by var and test R_NADAL item:
<h:form>
<p:selectOneMenu value="#{playerBean.selectedPlayerEnum}">
<f:selectItems value="#{enumpf | PlayerEnum.ALL_ENUM_VALUES}" var="t"
itemLabel="#{t.rank}" itemValue="#{t}" />
<p:ajax update="@form" />
</p:selectOneMenu>
#{playerBean.selectedPlayerEnum}
[#{playerBean.selectedPlayerEnum == enumpf | PlayerEnum.R_NADAL}]
</h:form>
Now, from OmniFaces’ perspective, things are very simple. Basically, we can import enums exactly as we have imported constants, via <o:importConstants/> tag handler. So, let’s see the above examples via OmniFaces now:
// expose enum in EL
<o:importConstants type="beans.PlayerEnum" />
<o:importConstants type="beans.PlayerEnum" var="enumof" />
// Loop enum values:
<ui:repeat value="#{enumof | PlayerEnum.values()}" var="t">
#{t}
</ui:repeat>
// Providing enum values as dropdown items and test R_NADAL item:
<h:form>
<p:selectOneMenu value="#{playerBean.selectedPlayerEnum}">
<f:selectItems value="#{enumof | PlayerEnum}" />
<p:ajax update="@form" />
</p:selectOneMenu>
#{playerBean.selectedPlayerEnum}
[#{playerBean.selectedPlayerEnum == enumof | PlayerEnum.R_NADAL}]
</h:form>
// Providing enum values as dropdown items by var and test R_NADAL item:
<h:form>
<p:selectOneMenu value="#{playerBean.selectedPlayerEnum}">
<f:selectItems value="#{enumof | PlayerEnum.values()}"
var="t" itemLabel="#{t.rank}" itemValue="#{t}" />
<p:ajax update="@form" />
</p:selectOneMenu>
#{playerBean.selectedPlayerEnum}
[#{playerBean.selectedPlayerEnum == enumof | PlayerEnum.R_NADAL}]
</h:form>
The complete application is named, PFOFImportEnums.
Import public static methods with OmniFaces
First of all you have to know that PrimeFaces Extensions doesn’t support this feature. In order to expose public static methods with a non void return type via EL, we can use the OmniFaces tag handler <o:importFunctions/>. This allows access to all functions of the given fully qualified name of a type in the Facelet scope using the usual EL functions syntax without the need to register them in *.taglib.xml file. We can use it exactly as <o:importConstants/>, by indicating in the required type attribute the fully qualified name of the class to import the public static non void methods for:
<o:importFunctions type="beans.PlayerHelper"/>
<o:importFunctions type="beans.PlayerHelper" var="funcof"/>
Is rank 1 in ATP available to play with me?
<h:outputLink id="playerId" value="#">
<h:outputText value="Rafael Nadal" />
</h:outputLink>
<p:tooltip for="playerId" value="Available:
#{funcof | PlayerHelper:isPlayerAvailable(1)}" />
The complete application is named, PFOFImportFunctions.
Do not forget to check out the OmniFaces Showcase. There you can read a brief dissertation on multiple functions with exactly the same method name and some design notes.