What's new in JSF 2.3?
The process of developing JSF 2.3 started late september 2014, which is approximately 1.5 half year after JSF 2.2 was finalized. JSF 2.3 went final in the beginning of 2017.
The following text describes the new features of JSF 2.3. Compiled by JSF 2.3 EG member Arjan Tijms.
JSF 2.3 new features
- CDI alignment
- Lifecycle
- Networking / AJAX
- Conversion / Validation
- Java API
- Components
- Views and Resources
- Type-safety
- Configuration
CDI
Injection and EL resolving of JSF artifacts (spec issue 1316) (partially)
JSF has traditionally used static entry methods and chaining to let the user obtain the various artifacts that it provides, such as the FacesContext, session map, external context, etc. The following gives a few examples of this:
FacesContext facesContext = FacesContext.getCurrentInstance() ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); Map<String, Object> cookieMap = FacesContext.getCurrentInstance().getExternalContext().getRequestCookieMap(); Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap(); // etc
Especially the artefacts that have to be obtained by deep chaining can be problematic. Not only makes this the code verbose and hard to read, it can also be unclear to users that the view map has to be obtained via the view root but the cookie map via the external context as shown above.
Furthermore, the pattern makes it hard to override what is returned by the runtime. In JSF it IS possible to influence this by providing/setting a custom FacesContext, but especially for the deeper chained artefacts multiple levels or wrapping are then required, which is not always trivial to implement. The problem there is clearly that the abstraction is at the wrong level; providing an alternative view map requires a custom faces context, which provides a wrapped view root, which then finally provides the view map we wanted to provide.
A more modern approach in Java EE is to inject artefacts in order to obtain them (essentially flattening the lookup) and to provide alternative producers for those when the need to override them arises.
JSF 2.3 will therefore provide default producers for the most important artefacts, which at the moment being:
Artefact | EL name | Qualifier | Type |
---|---|---|---|
Application | #{application} | - | java.lang.Object (javax.servlet.ServletContext) |
ApplicationMap | #{applicationScope} | @ApplicationMap | java.util.Map<String, Object> |
CompositeComponent | #{cc} | (Not injectable) | javax.faces.component.UIComponent |
Component | #{component} | (Not injectable) | javax.faces.component.UIComponent |
RequestCookieMap | #{cookie} | @RequestCookieMap | java.util.Map<String, Object> |
FacesContext | #{facesContext} | - | javax.faces.context.FacesContext |
Flash | #{flash} | - | javax.faces.context.Flash |
FlowMap | #{flowScope} | @FlowMap | java.util.Map<Object, Object> |
HeaderMap | #{header} | @HeaderMap | java.util.Map<String, String> |
HeaderValuesMap | #{headerValues} | @HeaderValuesMap | java.util.Map<String, String[]> |
InitParameterMap | #{initParam} | @InitParameterMap | java.util.Map<String, String> |
RequestParameterMap | #{param} | @RequestParameterMap | java.util.Map<String, String> |
RequestParameterValuesMap | #{paramValues} | @RequestParameterValuesMap | java.util.Map<String, String[]> |
Request | #{request} | (Not injectable) | java.lang.Object (javax.servlet.http.HttpServletRequest) |
RequestMap | #{requestScope} | @RequestMap | java.util.Map<String, Object> |
ResourceHandler | #{"resource"} | - | javax.faces.application.ResourceHandler |
Session | #{session} | (Not injectable) | java.lang.Object (javax.servlet.http.HttpSession) |
SessionMap | #{sessionScope} | @SessionMap | java.util.Map<String, Object> |
View | #{view} | - | javax.faces.component.UIViewRoot |
ViewMap | #{viewScope} | @ViewMap | java.util.Map<String, Object> |
ExternalContext | #{externalContext} (new) | - | javax.faces.context.ExternalContext |
The general types, in this case the maps, need an extra qualifier to avoid clashing with other producers. The JSF specific types however don't need such qualifier since JSF is the sole owner of these types.
Obtaining the JSF artefacts is therefore as easy as can be; one only needs to know the type of the artefact one wants. For example:
@Inject private ExternalContext context;
For the ones that do need a qualifier, this qualifier has to be looked-up of course, but that's essentially a flat lookup. For example:
@Inject @ApplicationMap private Map<String, Object> applicationMap;Furthermore, somewhat as a side-effect of Injection in more JSF artifacts, user created instances of the following artefacts are also injectable:
- Converter
- Validator
- Behavior
@Inject @FacesConverter(value = "myConverter", managed = true) private Converter myConverter;Note that this particular injection pattern is possible, but not entirely how things are normally done in CDI.
As far as the implementation side is concerned, there's a CDI Bean<T> instance (aka "default bean") provided for every artefact. Since the term "bean" already has a meaning in JSF and CDI is not profoundly clear about this term either, the RI implementation code calls them "dynamic producer", or just "producer". Maybe "factory" would be better, but that term has a bit of a history itself and we wanted to avoid using that one.
The following shows an example of a Bean<T>/dynamic producer for the HeaderValues artefact:
public class HeaderValuesMapProducer extends CdiProducer<Map<String, String[]>> { public HeaderValuesMapProducer() { super.name("headerValues") .scope(RequestScoped.class) .qualifiers(new HeaderValuesMapAnnotationLiteral()) .types( new ParameterizedTypeImpl(Map.class, new Type[]{String.class, String[].class}), Map.class, Object.class) .beanClass(Map.class) .create(e -> FacesContext.getCurrentInstance().getExternalContext().getRequestHeaderValuesMap()); } }
Injection in more JSF artifacts (spec issue 1316) (partially)
In JSF 2.1 very few JSF artifacts were injection targets. In JSF 2.2 injection was made possible in a huge amount of additional artefacts but the very ones where injection actually matters most, converters and validators, were mysteriously left in the cold.
In JSF 2.3 this has now finally been taken care of as the following artefacts have been added to the list of injection targets:
- javax.faces.convert.Converter
- javax.faces.validator.Validator
- javax.faces.component.behavior.Behavior
However, in contrast to the artefacts already on this list these new 3 are not automatically injection targets. They will only become so when a new attribute called "managed" on the corresponding annotations @FacesConverter, @FacesValidator and @Behavior is set to true. Furthermore all these 3 annotations have been upgraded to being CDI qualifiers by adding the @Qualified annotation to their definition.
The existing attributes of @FacesConverter, @FacesValidator and @Behavior have not been modified, meaning they are all *binding*, as is the new attribute "managed".
What happens behind the scenes now is that when JSF needs a converter it simply asks the CDI bean manager for a bean that implements Converter with a qualifier @FacesValidator that has the "managed" attribute set to true and the value (coverterId) or forClass attribute set to the right value (which is why it's important that these attributes are all binding).
It then wraps the bean returned by CDI in a delegating converter instance. This wrapper then delegates to the bean returned by CDI. This wrapper can be state-saved, but since the CDI bean is stored in a transient field it won't save&restore that. Instead, it will only save&restore the converterId or forClass. The restored wrapper will then use the JSF Application instance to ask for a converter with said converterId or forClass (which will go to CDI again, and will do the wrapping again, so we have a double wrapped converter at this point).
In effect the mechanism is essentially quite like the age old workaround of using an EL expression pointing to a managed bean for a converter or validator.
An example of a JSF 2.3 converter in which injection can take place:
@FacesConverter(value = "myConverter", managed = true) public class MyConverter implements Converter { @Inject private MyService service; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { // Convert string to Object here } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { // Convert Object to String here } }
Note that this new style converter must have a constructor as defined by CDI (a no-args one here) and the alternative constructor is not supported here.
Native managed beans annotations deprecated (spec issue 1417 )
With JSF 2.0 annotations were introduced for the JSF managed bean facility. These annotations were however controversial from the start. At approximately the same time as they were being designed, there was a parallel effort started to provide a universal managed bean specification.
Because of that, the package that the JSF managed beans annotations lived in contained the following disclaimer:
At the time of this writing, a forthcoming JCP effort is being planned to extract the specification for managed beans from JSF and place it into its own specification. To account for this effort and to avoid introducing classes into JSF 2.0 that would have to be deprecated when this effort is complete, implementations of JSF 2.0 are not required to implement the “Faces Managed Bean Annotation Specification for Containers Conforming to Servlet 2.5”. However, JSF implementations are strongly encouraged to implement this specification, as it provides significant improvements in ease of use.
Of course we all know the name of this effort now; CDI.
Although effectively deprecated from day one, the now called "native" managed beans annotations from JSF had one advantage over their CDI versions and that's that they could use the important view scope (which incidentally was also introduced in JSF 2.0). It would take until JSF 2.2 for an official CDI version of that scope.
With the CDI based view scope introduced in JSF 2.2, JSF's own native bean facility could have been deprecated, but for some reason it wasn't. Now in JSF 2.3 the package containing the annotations for this facility has finally been deprecated.
The importance of this is that developers will hopefully be less confused which annotation to use (most IDEs will warn about using a deprecated type), and that JSF can take the next step; propose the entire managed bean facility for pruning. Just as EJB entity beans had no use in EJB anymore with JPA available and thus were actually removed ("pruned"), there's simply no need for JSF anymore to be in the managed bean business. JSF is already a very large spec, so removing(*) a large and now unnecessary part of it may help bringing down its size to somewhat more manageable proportions.
(* technically the pruned part of the spec will remain in existence and vendors are free to optionally implement it. The RI will always keep implementing it. So pruned does not mean "totally gone".)
CDI compatible @ManagedProperty (spec issue 1418 )
With JSF 2.3 deprecating the native managed beans annotations in favour of CDI, there was one useful feature left that didn't had a full CDI compatible replacement; @ManagedProperty.
JSF co-spec lead Manfred Riem provided a simple example for a String based CDI compatible version, of which JSF 2.3 will incorporate a variant that supports basically all data types. Just like the native version type checking is delayed till runtime.
Because of the delayed type checking it not rarely makes more sense to use regular CDI injection (with optionally qualifiers if needed), but for migrating existing code or for those situations where an EL expression really is more convenient the new @ManagedProperty from the javax.faces.annotation package can be used in CDI beans.
The following shows an example:
import javax.enterprise.context.RequestScoped; import javax.faces.annotation.ManagedProperty; import javax.inject.Inject; import javax.inject.Named; @Named @RequestScoped public class MyBean { @Inject @ManagedProperty("#{someBean.someProperty}") private Integer injectedInteger1; }
Lifecycle
System event published after view rendered (spec issue 1135)
JSF 2 introduced the concept of system events, which are events that can be fired by arbitrary objects at arbitrary points during the request processing lifecycle.
In JSF 2.2 there are some 20 events defined, e.g. PostAddToViewEvent, PostConstructViewMapEvent, PreValidateEvent, and specifically PreRenderViewEvent.
However, while there's a PreRenderViewEvent that's published right before a view is rendered, there's no event published right after. Such event can be useful for a variety of things, such as per view clean-ups, post rendering view processing, state handling, etc.
For these reasons and simply to be more consistent JSF 2.3 will add a new event called the PostRenderViewEvent, which as its name implies is published immediately after a view is rendered.
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"> <h:body> <f:event type="postRenderView" listener="#{myBean.doPostProcessing}" /> <!-- Rest of view here --> </h:body> </html>
Networking / AJAX
WebSocket integration (spec issue 1396)
WebSocket support for JSF has been talked about for quite some time, and there are fairly advanced implementations available by now.
Still, just as with the AJAX support that was added in JSF 2.0 and was available in proprietary component libraries before that, WebSocket support was seen as fundamental enough to be put directly into the core spec.
Therefor JSF 2.3 will provide direct support for WebSockets via the new tag <f:websocket>.
An important detail of the JSF 2.3 implementation of WebSocket support is that it uses the WebSocket JSR and therefor integrates with the WebSocket support offered by the server on which JSF is running. Proprietary implementations are not rarely based on frameworks such as Atmosphere. Both approaches have their own cons and pros, and just as with AJAX support the user can typically choose what to use; the version offered by core JSF, or the one by a component library.
The tag supports a number of attributes, of which the primary required attribute is "channel". The value set here can be used to send notifications to, which will then be pushed to all instances of the socket with that channel name. The second required attribute is "onmessage". Here a client-side Javascript event handler can be set that is called whenever a push arrives from the server.
The following shows a minimal example of using the tag on a JSF view:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html" > <h:head> Websocket Example </h:head> <h:body> <f:websocket channel="myChannel" onmessage="function(message){alert(message)}" /> </h:body> </html>
Receiving messages is one part of the process. The other part is of course to push out a message. This can be done via the new javax.faces.push.PushContext, which can be injected anywhere where CDI is available. The following shows an example:
@Named @RequestScoped public class SomeBean { @Inject @Push private PushContext myChannel; public void send(){ myChannel.send("Hello, from the server by push!"); } }
The injected PushContext is associated with one specific named channel, which by default has the same name as the instance variable in which injection takes place ("myChannel" in the example above).
Integration between JSF and WebSocket revealed one spec related problem; the WebSocket spec now assumes that the application has statically defined a so-called EndPoint via java code. In the case of <f:websocket> such required EndPoint has to be created in a more dynamic way, during runtime, or at the very least allow a (CDI) extension to define one. Unfortunately neither is possible now, at least not officially (some implementations support it anyway).
For those implementations that do not support adding an EndPoint dynamically (at the moment only GlassFish/Tyrus), a fake one has to be defined by the application. This kind of end point server no other function than to activate the container's WebSocket implementation. At the moment this is only known to be needed for GlassFish. On Tomcat and JBoss (WildFly/Undertow) this is not needed.
The following is an example of this:
public class FakeEndpoint extends Endpoint { @Override public void onOpen(Session session, EndpointConfig config) {} }
We will try to resolve this issue with the WebSocket EG, but due to the Java EE 8 hiatus it's unfortunately profoundly difficult to start a MR or revision for any spec that hasn't started one. As an alternative we may look into defining an SPI that each container that incorporates Mojarra has to implement, and in which WebSocket activation can be done in a proprietary way.
Due to unfinished work with the CDI integration, the following parameter now has to be set (to avoid clashes with a deprecated but still used switch that looks at the 2.3 version of a faces-config.xml file, if any).
<context-param> <param-name>javax.faces.ENABLE_CDI_RESOLVER_CHAIN</param-name> <param-value>true</param-value> </context-param>While the fake end point is used to initialise the container, the actual WebSocket end point needs to be started as well. This can't be done by default, since otherwise there will be an open socket even when WebSocket is never used. Fully dynamically creating the end point whenever an <f:websocket> is encountered is unfortunately even harder. Therefor another setting needs to be used:
<context-param> <param-name>javax.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name> <param-value>true</param-value> </context-param>
Further reading:
Ajax method invocation (spec issue 613)
One of many major new features in JSF 2.0 was core support for Ajax. This effectively standardised what legendary libraries such as A4J had been doing in the years prior to that version.
One particular feature that almost every Ajax library supported wasn't standardised though. That feature is the ability to call an arbitrary server side method in a bean via Ajax. JSF 2.3 will address this omission by introducing the new <h:commandScript> component. Though many JSF libraries have something similar to this, <h:commandScript> was most directly based on the <o:commandScript> component from OmniFaces.
Simply said, the component creates a javascript function with a given name that once invoked will invoke on its turns the also given server side method via Ajax. The following shows an example:
<h:form> <h:commandScript name="myJsClientFunction" action="#{myBean.myJavaServerMethod('bar')}" render=":output" /> </h:form> <h:outputText id="output" value="#{myBean.output}" />
In the example above the client side javascript myJsClientFunction will effectively be connected to the server side Java myJavaServerMethod method.
Execute javascript from server at completion of AJAX response (spec issue 1412)
It's often quite convenient to be able to execute a piece of javascript coming from the server right after an AJAX response has been applied on the client. Various popular component libraries such as PrimeFaces and OmniFaces have their own utilities to let the developer do exactly this.
Since AJAX was introduced in JSF there technically has been some level of core support for this. Namely, the <partial-response> payload that JSF sends after an AJAX request has an <eval> section where javascript can be put for execution on the client. The response writer used for writing the partial response even had startEval and endEval methods for these, but mysteriously for about 7 years(!) those methods remained totally unused and were probably largely forgotten.
In JSF 2.3 those methods were rediscovered, and a new method was added to the PartialViewContect; List<String> getEvalScripts().
Using this new getEvalScripts() method, a JSF backing bean handling an AJAX request can easily add a piece of javascript to the AJAX response. The following shows an example:
Within a form on some view:
<h:commandButton value="submit" action="#{someBean.eval}"> <f:ajax /> </h:commandButton>Backing bean:
@Named @RequestScoped public class SomeBean { @Inject private FacesContext context; public void eval() { context.getPartialViewContext() .getEvalScripts() .add("alert('After response')"); } }
After pushing the button shown above, an alert with the text "After response" in it will be shown. Note that while in the example above the piece of javascript is the only thing in the payload of the response, one would normally combine this with updating data and rerendering one or more parts of the view.
Updating multiple forms via AJAX (spec issue 790)
Via the AJAX support that was introduced in JSF 2.0 it was made possible to selectively update one or more components and the children of those components. Since the beginning of JSF it has been possible for a view to use multiple (non-nested) forms, and this is in fact a quite common thing in JSF applications.
Curiously though, these 2 very common features didn't work at all together as was discovered soon after AJAX support was added to JSF in 2009. What happens is that in JSF each form needs a hidden input field for the view state. This field is normally added in a somewhat non-trivial way, which is e.g. the reason a caching component can't directly cache a form. Now the AJAX partial-response from JSF 2.0 didn't take this fact into account at all, and would just contain the markup of the updated form without the view state field (which incidentally is exactly what you would get when using a caching or buffering component on a form).
The partial-response did contain the updated view state value, but strangely enough the spec said that this should only be used to update the view state field of the submitting form. This may have been a mistake or an oversight at the time.
The result is that after an AJAX update that involves the update of multiple forms (directly or via their parent components), the view is left in a broke state. JSF forms without the view state field present simply don't work. Mojarra provided a limited implementation specific fix where you had to explicitly specify all forms to be updated (even if you were updating a single parent of all those forms), and some libraries like OmniFaces provided a limited fix as well.
Part of the problem why this is a difficult issue to fix is the fact that JSF can also be used in a Portlet environment. In such environment it's not possible to have a javascript just update all JSF forms that it finds, as these may belong to different Portlets (the markup rendered by different Portlets is all part of the same HTML document with very little to no browser enforced isolation between them).
Below is an example of this problem. First consider the following view:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head/> <h:body> <h:panelGroup id="panel1" layout="block"> <h:form id="form1"> <h:commandButton id="button" value="submit form1 and render panel2"> <f:ajax execute=":form1" render=":panel2" /> </h:commandButton> </h:form> </h:panelGroup> <h:panelGroup id="panel2" layout="block"> <h:form id="form2"> <h:commandButton id="button" value="submit form2 and render panel1"> <f:ajax execute=":form2" render=":panel1" /> </h:commandButton> </h:form> </h:panelGroup> </h:body> </html>
Using Mojarra 2.2.13 (on Payara 4.1.1.162) clicking the first button will result in the following partial response to be send:
<?xml version='1.0' encoding='UTF-8'?> <partial-response id="j_id1"> <changes> <update id="panel2"> <![CDATA[ <div id="panel2"> <form id="form2" name="form2" method="post" action="/test-javaee8-ajax/spec790.xhtml" enctype="application/x-www-form-urlencoded"> <input type="hidden" name="form2" value="form2" /> <input id="form2:button" type="submit" name="form2:button" value="submit form2 and render panel1" onclick="mojarra.ab(this,event,'action','form2','panel1');return false" /> </form> </div> ]]> </update> <update id="j_id1:javax.faces.ViewState:0"> <![CDATA[8345405308944877647:7731292386533209235]]> </update> </changes> </partial-response>
<html xmlns="http://www.w3.org/1999/xhtml"> <head id="j_idt3"> <script type="text/javascript" src="/test-javaee8-ajax/javax.faces.resource/jsf.js.xhtml?ln=javax.faces"></script> </head> <body> <div id="panel1"> <form id="form1" name="form1" method="post" action="/test-javaee8-ajax/spec790.xhtml" enctype="application/x-www-form-urlencoded"> <input type="hidden" name="form1" value="form1"> <input id="form1:button" type="submit" name="form1:button" value="submit form1 and render panel2" onclick="mojarra.ab(this,event,'action','form1','panel2');return false"> <input type="hidden" name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="6782127948134886858:-5613250933960587439" autocomplete="off"> </form> </div> <div id="panel2"> <form id="form2" name="form2" method="post" action="/test-javaee8-ajax/spec790.xhtml" enctype="application/x-www-form-urlencoded"> <input type="hidden" name="form2" value="form2"> <input id="form2:button" type="submit" name="form2:button" value="submit form2 and render panel1" onclick="mojarra.ab(this,event,'action','form2','panel1');return false"> </form> </div> </body> </html>
This problem is solved in JSF 2.3 by introducing a "namespaced mode" and a "non namespaced mode", which is the default.
In namespaced mode, which is specifically intended for Portlets but can be used in other environments as well, the partial response is given an id that's taken to be the "naming container id". All predefined postback parameter names (such as "javax.faces.ViewState", "javax.faces.ClientWindow", "javax.faces.RenderKitId", etc) are prefixed with this and the naming separator (default ":"). e.g. javax.faces.ViewState" becomes "myname:javax.faces.ViewState". Namespaced mode is activated when the UIViewRoot instance implements the NamingContainer interface.
In non namespaced mode the partial response does not have an id and the "naming container id" is set to be the empty string (""). All predefined postback parameters have their normal name.
In both cases, the "jsf.js" script handles a partial response by updating all forms where the method is "post", the id attribute is present and that id attribute starts with the "naming container id". In case of non namespaced mode this will thus match every form with an id.
Using Mojarra 2.3-m07 (on Payara 4.1.1.162) and the non namespaced mode clicking the first button on the view shown above will now result in the following partial response to be send:
<?xml version='1.0' encoding='UTF-8'?> <partial-response> <changes> <update id="panel2"> <![CDATA[ <div id="panel2"> <form id="form2" name="form2" method="post" action="/test-javaee8-ajax/spec790.xhtml" enctype="application/x-www-form-urlencoded"> <input type="hidden" name="form2" value="form2" /> <input id="form2:button" type="submit" name="form2:button" value="submit form2 and render panel1" onclick="mojarra.ab(this,event,'action','form2','panel1');return false" /> </form> </div> ]]> </update> <update id="j_id1:javax.faces.ViewState:0"> <![CDATA[-8282461998981779774:413768236226206985]]> </update> </changes> </partial-response>
<html xmlns="http://www.w3.org/1999/xhtml"> <head id="j_idt3"> <script type="text/javascript" src="/test-javaee8-ajax/javax.faces.resource/jsf.js.xhtml?ln=javax.faces"></script> </head> <body> <div id="panel1"> <form id="form1" name="form1" method="post" action="/test-javaee8-ajax/spec790.xhtml" enctype="application/x-www-form-urlencoded"> <input type="hidden" name="form1" value="form1"> <input id="form1:button" type="submit" name="form1:button" value="submit form1 and render panel2" onclick="mojarra.ab(this,event,'action','form1','panel2');return false"> <input type="hidden" name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="2250188649944914411:-7175801439454851104" autocomplete="off"> </form> </div> <div id="panel2"> <form id="form2" name="form2" method="post" action="/test-javaee8-ajax/spec790.xhtml" enctype="application/x-www-form-urlencoded"> <input type="hidden" name="form2" value="form2"> <input id="form2:button" type="submit" name="form2:button" value="submit form2 and render panel1" onclick="mojarra.ab(this,event,'action','form2','panel1');return false"> <input type="hidden" name="javax.faces.ViewState" value="2250188649944914411:-7175801439454851104"> </form> </div> </body> </html>
In namespaced mode running a similar view as shown above and pressing the button again will yield the following response:
<?xml version='1.0' encoding='UTF-8'?> <partial-response id="j_id1"> <changes> <update id="j_id1:panel2"> <![CDATA[ <div id="j_id1:panel2"> <form id="j_id1:form2" name="j_id1:form2" method="post" action="/test-javaee8-namespacedView/spec790.xhtml" enctype="application/x-www-form-urlencoded"> <input type="hidden" name="j_id1:form2" value="j_id1:form2" /> <input id="j_id1:form2:button" type="submit" name="j_id1:form2:button" value="submit form2 and render panel1" onclick="mojarra.ab(this,event,'action','j_id1:form2','j_id1:panel1');return false" /> </form> </div> ]]> </update> <update id="j_id1:javax.faces.ViewState:0"> <![CDATA[-8822830692037537003:-3037874094673406621]]> </update> </changes> </partial-response>
<html xmlns="http://www.w3.org/1999/xhtml"><head id="j_id1:j_idt3"> <script type="text/javascript" src="/test-javaee8-namespacedView/javax.faces.resource/jsf.js.xhtml?ln=javax.faces"></script> </head> <body> <div id="j_id1:panel1"> <form id="j_id1:form1" name="j_id1:form1" method="post" action="/test-javaee8-namespacedView/spec790.xhtml" enctype="application/x-www-form-urlencoded"> <input type="hidden" name="j_id1:form1" value="j_id1:form1"> <input id="j_id1:form1:button" type="submit" name="j_id1:form1:button" value="submit form1 and render panel2" onclick="mojarra.ab(this,event,'action','j_id1:form1','j_id1:panel2');return false"> <input type="hidden" name="j_id1:javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="6924255192267784760:-4075825978563358382" autocomplete="off"> </form> </div> <div id="j_id1:panel2"> <form id="j_id1:form2" name="j_id1:form2" method="post" action="/test-javaee8-namespacedView/spec790.xhtml" enctype="application/x-www-form-urlencoded"> <input type="hidden" name="j_id1:form2" value="j_id1:form2"> <input id="j_id1:form2:button" type="submit" name="j_id1:form2:button" value="submit form2 and render panel1" onclick="mojarra.ab(this,event,'action','j_id1:form2','j_id1:panel1');return false"> <input type="hidden" name="j_id1:javax.faces.ViewState" value="6924255192267784760:-4075825978563358382"> </form> </div> </body> </html>
By taking the namespaced ids into account, all forms can now be safely updated in a Portlets environment as well.
Conversion / Validation
Class level bean validation (spec issue 1)
JSF has supported bean validation ever since JSF 2.0 was released. This support was however limited to validating individual properties bound to individual components. E.g. an input component bound to a password property of a backing bean.
Besides validating individual fields or properties, bean validation also has a concept of class level validation. This involves a special constraint validator that receives an instance of the class that has to be validated. This special validator can then do cross-field validations. For instance, check that two password fields are equal.
Class level validation does not play well with the JSF validation model though. In JSF the idea is that the model is not touched if validation fails. But to validate a class level constraint, we have to update the model with all values before proceeding. This problem was solved in OmniFaces by making a copy of the bean, storing the new values in that bean, and then validating the result.
This approach and some of the code have been standardized in JSF 2.3 by means of a new tag: <f:validateWholeBean>
Class level bean validation practically speaking most often applies to entities that have their own semantic constraints with associated validation code. Typically such entity is returned fully from a backing bean, but the properties of such entity are then bound to individual components. The OmniFaces example of class level bean validation demonstrates exactly this.
Another possibility is a more ad-hoc class level validation, for instance done by a backing bean. This can be used as a multi-field validator, where the multiple fields being validated are not necessarily part of a more structural and re-usable constraint. This usecase is in fact the major driver behind the very first JIRA issues for JSF; JAVASERVERFACES_SPEC_PUBLIC-1 which was filed in 2004!
Using class level bean validation for this usecase is slightly verbose and perhaps not a fully ideal match, but it does align well with the current strategy of delegating as much concerns as possible to existing functionality in Java EE instead of introducing native mechanisms that partially overlap with that existing functionality. We show an example of this below.
First of all, the new tag must be explicitly enabled in web.xml. If it's not enabled, the tag will do nothing. The following setting will take care of this:
<context-param> <param-name>javax.faces.validator.ENABLE_VALIDATE_WHOLE_BEAN</param-name> <param-value>true</param-value> </context-param>
After this initial nuasance we can create a view with two input fields, and the mentioned <f:validateWholeBean> tag. There are a few things to be aware of here:
- At least one input component in the view must have a bean validation group set
- The <f:validateWholeBean> tag must appear AFTER all other input components
- The group for the input component(s) and the <f:validateWholeBean> tag must be the same
- The special default group (javax.validation.groups.Default) does not count, it's explicitly ignored.
The following gives an example:
<h:form> <h:inputText value="#{indexBean.foo}"> <f:validateBean validationGroups="javax.validation.groups.Default,java.util.RandomAccess"/> </h:inputText> <h:inputText value="#{indexBean.bar}"> <f:validateBean validationGroups="javax.validation.groups.Default,java.util.RandomAccess"/> </h:inputText> <f:validateWholeBean value="#{indexBean}" validationGroups="java.util.RandomAccess"/> <h:commandButton value="submit"/> </h:form>
In order to keep the example as small as possible I re-used an existing "random" interface for the group marker. Note that the default group javax.validation.groups.Default is also added to make sure individual fields are still bean validated as well.
Next thing is the backing bean itself. In order to use class level bean validation the following has to be done:
- An annotation has to be defined that adheres to the bean validation spec for class level constraints
- A constraint validator implementation has to be provided, which takes care of the actual validation
- The backing bean has to be annotated with that annotation
- The annotation's groups attribute has to be set to the same group that was used in the view
@Named @RequestScoped @ValidIndexBean(groups = java.util.RandomAccess.class) public class IndexBean implements ConstraintValidator<ValidIndexBean, IndexBean> { @Constraint(validatedBy = IndexBean.class) @Documented @Target(TYPE) @Retention(RUNTIME) public @interface ValidIndexBean { String message() default "Invalid Bean"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } @Override public void initialize(ValidIndexBean constraintAnnotation) { // } @Override public boolean isValid(IndexBean other, ConstraintValidatorContext context) { return other.getFoo().equals(other.getBar()); } @NotNull private String foo; @NotNull private String bar; public String getFoo() { return foo; } public void setFoo(String foo) { this.foo = foo; } public String getBar() { return bar; } public void setBar(String bar) { this.bar = bar; } }
As mentioned this is indeed slightly verbose for a one-off multiple fields validation. Specifically the verbosity of the annotation is hard to reduce in this case. A default annotation for cases like this would probably help a lot, but at the moment there's none (at least not that I know of). The unneeded initialize method could be solved if the bean validation spec used a default method in the interface for this. Unfortunately there's no bean validation spec update or even MR planned at the moment.
Note that the other instance that the isValid method receives is a "copy" of the same bean. However, currently it's not really a copy but a new instance. The JSF 2.3 implementation code principally has the same copiers available as the ones for the OmniFaces version, but because of what seems to be a bug only the so-called NewInstanceCopier actually seems to be used in practice. Unlike in OmniFaces, it's also not currently possible to explicitly select a copier strategy or provide a custom one.
Further reading:
JDK 8 time support in f:convertDateTime (spec issue 1370)
JSF 2.3 will have Java 8 as a minimum dependency. One of the big advantages of this is that it's actively able to support new features in Java 8. One of those features concern the new data and time classes in JDK 8, otherwise known as JSR 310.
JSF 2.3 will provide support for these using its existing <f:convertDateTime> converter. In JSF 2.2 and before the type attribute of this converter only supported the values "date", "time" and "both". For JSF 2.3 this has been expanded with various values as shown in the table below:
Type attribute | Class involved | Default when pattern not specified |
---|---|---|
both | java.util.Date | DateFormat.getDateTimeInstance(dateStyle, timeStyle) |
date | java.util.Date | DateFormat.getDateTimeInstance(dateStyle) |
time | java.util.Date | DateFormat.getDateTimeInstance(timeStyle) |
localDate | java.time.LocalDate | DateTimeFormatter.ofLocalizedDate(dateStyle) |
localTime | java.time.LocalTime | DateTimeFormatter.ofLocalizedTime(dateStyle) |
localDateTime | java.time.LocalDateTime | DateTimeFormatter.ofLocalizedDateTime(dateStyle) |
offsetTime | java.time.OffsetTime | DateTimeFormatter.ISO_OFFSET_TIME |
offsetDateTime | java.time.OffsetDateTime | DateTimeFormatter.ISO_OFFSET_DATE_TIME |
zonedDateTime | java.time.ZonedDateTime | DateTimeFormatter.ISO_ZONED_DATE_TIME |
In addition the pattern attribute has changed as well. In JSF 2.2 when this pattern attribute was set, the other attributes were ignored and java.text.SimpleDateFormat was used exclusively. In JSF 2.3 if the type attribute is set to any of the new JDK 8/JSR 310 values then java.time.format.DateTimeFormatter will be used instead. In all cases the pattern attribute still overrides the timeStyle and dateStyle attributes.
Example of usage:
<h:inputText value="#{myBean.startTime}"> <f:convertDateTime type="localDateTime" /> </h:inputText> <h:outputText value="#{myBean.endDate}"> <f:convertDateTime type="localDate" pattern="dd.MM.uu" /> </h:outputText>
Further reading:
Java API
Support for the Iterable interface in UIData and UIRepeat (spec issue 1103)
From the beginning of JSF, the UIData component (known from e.g. <h:dataTable>) and UIRepeat (known from e.g. <ui:repeat>) only realistically supported the List, native array and JSF specific DataModel as input for its value binding. This meant other collection types had to be expressed as one of these types.
In JSF 2.2 UIData was extended to support Collection as well, but UIRepeat was mysteriously left out (which is one reason why UIRepeat should really share common functionality with UIData; it happens much more often that both should be updated but only one of them is)
The thing is that while Collection support is nice, it's actually just as easy to support Iterable. It's perhaps a small oversight that this was not supported right from the beginning, but in JSF 2.3 this will finally be addressed.
Just as with the Collection support in 2.2, Iterable will be added to the bottom of the list of types being checked, so for Iterables that are also a List or Collection (in case of UIData), the existing code will take precedence.
The following are now the supported types for UIData:
- null (becomes empty list)
- javax.faces.model.DataModel
- java.util.List
- java.lang.Object[]
- java.sql.ResultSet
- javax.servlet.jsp.jstl.sql.Result
- java.util.Collection
- java.lang.Iterable new!
- java.lang.Object (becomes ScalarDataModel)
And the following are the supported types for UIRepeat:
- null (becomes empty list)
- javax.faces.model.DataModel
- java.util.List
- java.lang.Object[]
- java.sql.ResultSet
- java.lang.Iterable new!
- java.lang.Object (becomes ScalarDataModel)
Note that both Result and Collection are missing for UIRepeat. The latter will be handled by Iterable, since it's the base class of Collection. Result is actually missing, likely because its JSP specific and UIRepeat was designed specifically for Facelets).
Support for the Map interface in UIData and UIRepeat (spec issue 1364)
Besides support for the Iterable interface in UIData and UIRepeat, JSF 2.3 will also add support for maps. The way this is done is closely aligned with how JSTL has supported maps for many years:
Existing JSTL based looping through a map
<c:forEach var="entry" items="${myMap}"> Key: <c:out value="${entry.key}"/> Value: <c:out value="${entry.value}"/> </c:forEach>New JSF 2.3 based looping through a map using ui:repeat
<ui:repeat var="entry" value="#{myMap}"> Key: #{entry.key} Value: #{entry.value} </ui:repeat>New JSF 2.3 based looping through a map using h:dataTable
<h:dataTable var="entry" value="#{myMap}"> <h:column>#{entry.key}</h:column> <h:column>#{entry.value}</h:column> </h:dataTable>
Including the Iterable support from the previous feature and the Map support discussed here, the following are now the supported types for UIData:
- null (becomes empty list)
- javax.faces.model.DataModel
- java.util.List
- java.lang.Object[]
- java.sql.ResultSet
- javax.servlet.jsp.jstl.sql.Result
- java.util.Collection
- java.lang.Iterable new!
- java.util.Map new!
- java.lang.Object (becomes ScalarDataModel)
And the following are the supported types for UIRepeat:
- null (becomes empty list)
- javax.faces.model.DataModel
- java.util.List
- java.lang.Object[]
- java.sql.ResultSet
- java.lang.Iterable new!
- java.util.Map new!
- java.lang.Object (becomes ScalarDataModel)
Support for custom types in UIData and UIRepeat (spec issue 1078)
A third new feature in JSF 2.3 next to support for the Iterable interface in UIData and UIRepeat, and support for the Map interface in UIData and UIRepeat is support for custom types.
This has been requested for a long time, and JSF 2.3 will now (finally) provide this support. The way this is done is by creating a wrapper DataModel for a specific type, just as one may have done years ago when returning data from a backing bean, and then annotating it with the new @FacesDataModel annotation. A “forClass” attribute has to be specified on this annotation that designates the type this wrapper is able to handle.
The following gives an abbreviated example of this:
@FacesDataModel(forClass = MyCollection.class) public class MyCollectionModel<E> extends DataModel<E> { @Override public E getRowData() { // access MyCollection here } @Override public void setWrappedData(Object myCollection) { // likely just store myCollection } // Other methods omitted for brevity }
Note that there are two types involved here. The “forClass” attribute is the collection or container type that the DataModel wraps, while the generic parameter E concerns the data this collection contains. E.g. Suppose we have a MyCollection<User>, then “forClass” would correspond to MyCollection, and E would correspond to User. If set/getWrappedData was generic the “forClass” attribute may not have been needed, as generic parameters can be read from class definitions, but alas.
With a class definition as given above present, a backing bean can now return a MyCollection as in the following example:
@Named public class MyBacking { public MyCollection<User> getUsers() { // return myCollection } }h:dataTable will be able to work with this directly, as shown in the example below:
<h:dataTable value="#{myBacking.users}" var="user"> <h:column>#{user.name}</h:column> </h:dataTable>
Further reading:
Default getWrapped method for FacesWrapper implementations (spec issue 1429)
JSF has an interface called FacesWrapper that's "implemented" by the more concrete wrappers such as ApplicationWrapper, ResourceHandlerWrapper, etc.
In JSF 2.2 and before the getWrapped() method from the FacesWrapper wasn't actually implemented though, but this was left open for the actual sub class of these wrappers to do. E.g. they had to add something like shown below for say the ResourceWrapper:
public class MyResourceWrapper extends ResourceWrapper { private Resource wrapped; public MyResourceWrapper(Resource wrapped) { this.wrapped = wrapped; } @Override public Resource getWrapped() { return wrapped; } }Not only is this a small amount of extra verbosity that needs to be added to every wrapper, it also encourages using the wrapped instance variable directly. This can be quite problematic when the wrapper itself is wrapped, something which is not that uncommon in practice.
In JSF 2.3 all standard FacesWrappers will therefor provide a default implementation of the getWrapped() method, and will introduce a new constructor that takes the artefact being wrapped as an argument. The no-args constructor is being deprecated so the IDE or compiler can issue a warning when the new super constructor is not being used by subclasses. All existing code in the RI has been updated to use the getWrapped() method exclusively instead of the instance variable they may have been using before.
The following shows an example:
public class MyResourceWrapper extends ResourceWrapper { public MyResourceWrapper(Resource wrapped) { super(wrapped); } }
Components
Component Search Expression framework (spec issue 1238)
JSF has always had a concept of identifying a particular component in its component tree by using an absolute hierarchical ID, or a relative local ID. Constructing the absolute ID is not always easy, especially not if a page makes extensive use of templates and includes.
To somewhat alleviate these difficulties, JSF 2.0 introduced a couple of more abstract search expressions, namely: @this", "@form", "@all", and "@none". Something like "@form" is particularly easier to use, as it just means; target whatever the current form is. If that current form is defined two parent templates up from the page where its referenced, this really makes referencing it much easier.
While making things much easier, these keywords were quite limited. Not only are there just 4 of them, they're also not extensible and the default component set only uses them in the f:ajax tag. Using them in Other tags, as well as using them when programmatically searching for components was left out.
Therefor in JSF 2.3 a "Component Search Expression framework" is introduced that greatly expands upon those 4 keywords. Summarised what it brings is:
- Larger set of default keywords
- Keywords can have arguments
- Keywords are extendible
- Keywords can be chained, forming search expressions
- More default tags support these
- Can be used via a programmatic API
New keywords
The following table lists the new keywords:
Keyword | Description |
---|---|
@child(n) | The nth child of the base component |
@composite | The closest composite component ancestor of the base component |
@id(id) | All component descendants of the base component with the specified component id |
@namingcontainer | The closest NamingContainer ancestor of the base component |
@next | The next component in the view after the base component |
@parent | The parent of the base component |
@previous | The previous component to the base component |
@root | The UIViewRoot |
For some examples, consider the following page fragment:
<h:body id="body"> <h:panelGroup id="panelgroup"> <h:form id="form"> <h:button id="button" outcome="foo2">Button foo</h:button> <h:commandButton id="commandButton" action="#{configurationBean.foo()}" value="invoke foo"/> <h:outputText id="body" value="body"/> </h:form> </h:panelGroup> </h:body>
The following table shows what several expressions against the above shown fragment resolve to:
Expression | Base component | Resolves to: |
---|---|---|
@child(0) | :form | <h:button id="button" outcome="foo2">Button foo</h:button> |
@child(1) | :form | <h:commandButton id="commandButton" action="#{configurationBean.foo()}" value="invoke foo"/> |
@id(body) | :form | <h:outputText id="body" value="body"/> |
@namingcontainer | :form:commandButton | <h:form id="form"> |
@next | :form:commandButton | :<h:outputText id="body" value="body"/> |
@parent | :form | <h:panelGroup id="panelgroup"> |
@previous | :form:commandButton | <h:button id="button" outcome="foo2">Button foo</h:button> |
@root | :form | [UIViewRoot] |
Programmatic API
A major new feature of the Component Search Expression framework is that it brings with it a programmatic API. The main elements of this are the SearchExpressionContext, which can be created via the static method SearchExpressionContext#createSearchExpressionContext and the SearchExpressionHandler which can be obtained from the existing JSF Application instance.
This API allows us among others to obtain the ID of a component we're searching for, or to execute a method on it in context. Several visit hints are supported as well. The following shows a basic example:
@Named @RequestScoped public class ConfigurationBean { @Inject private FacesContext context; public void foo() { SearchExpressionContext searchContext = createSearchExpressionContext(context, context.getViewRoot()); context.getApplication() .getSearchExpressionHandler() .resolveComponent( searchContext, ":form:@parent", (context, target) -> out.print(target.getId())); } }The code above first creates the SearchExpressionContext , and then uses the SearchExpressionHandler to obtain the parent of a component with the absolute id "foo" (this demonstrates a chained expression). When this is a found, a lambda is executed against it which just prints its ID.
Extendible API
Another major new feature of the Component Search Expression framework is that keywords are extensible. This works by creating an implementation of SearchKeywordResolver which in its simplest form has 2 important methods to implement: a method that recognises the keyword name and optionally its attributes, and a method that contains the component search logic.
A custom SearchKeywordResolver has to be registered with the JSF Application instance before the first request is served (for instance by using a ServletContextListener). A new SearchKeywordResolver will be added before all existing resolvers, so resolvers that are added later override those are added earlier, including the resolvers for the default keywords.
The following shows an example:
Implementation:
public class GrandParentKeywordResolver extends SearchKeywordResolver { @Override public boolean isResolverForKeyword(SearchExpressionContext searchExpressionContext, String keyword) { return "grandParent".equals(keyword); } @Override public void resolve(SearchKeywordContext searchKeywordContext, UIComponent current, String keyword) { UIComponent parent = current.getParent(); if (parent != null) { searchKeywordContext.invokeContextCallback(parent.getParent()); } else { searchKeywordContext.setKeywordResolved(true); } } }
Registration:
@WebListener public class WebInit implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { FacesContext.getCurrentInstance() .getApplication() .addSearchKeywordResolver(new GrandParentKeywordResolver()); } }
The example above causes a new keyword to become available for usage, namely "@grandParent", which attempts to find the parent of the parent of a base component. This is of course just intended as a simple example, but it demonstrates how easy it is to extend the set of search expression keywords.
Freely placeable radio button component (spec issue 329)
An omission in JSF that has been missed by JSF developers since the dawn of time is a simple radio button that's part of a group and can be placed anywhere on a page. Core JSF does support radio buttons, but they are always rendered together in a table. Needless to say this isn't always what is desired.
Even before the release of JSF 2.0 in 2009 quite an amount of external component libraries provided a radio button component that could be placed freely on a page. Granted, core JSF does not aim to be provide a rich set of components (this is left to those external libraries), but it does aim to provide a very basic set that maps fairly directly to the basic HTML elements. Given that a freely placeable radio button is so basic and given that it has been implemented so many times over by different vendors makes it an ideal candidate for standardisation, but for JSF's long life time this just never came to be.
But, finally, JSF 2.3 will provide support for this via the introduction of a new group attribute. Using that, radio buttons (h:selectOneRadio) can be rendered individually, while sharing the selection with all other buttons in the same group.
The following shows an example where there's only 1 radio button component in the view, but it's physically rendered in a new row for every iteration of the data table:
<h:dataTable id="table" value="#{myBean.myValues}" var="val"> <h:column> <h:selectOneRadio id="radio" group="someGroup" value="#{myBean.selectedvalue}"> <f:selectItem itemValue="#{val}" /> </h:selectOneRadio> </h:column> </h:dataTable>
Labels are optionally. The above example didn't use one, but one can be added via the h:outputLabel component:
<h:dataTable id="table" value="#{myBean.myValues}" var="val"> <h:column> <h:outputLabel for="radio" value="#{val.name}" /> <h:selectOneRadio id="radio" group="someGroup" value="#{myBean.selectedvalue}"> <f:selectItem itemValue="#{val}" /> </h:selectOneRadio> </h:column> </h:dataTable>In addition to that it's possible to distribute a select items collection over multiple radio button components within the same group:
<h:selectOneRadio id="radio0" group="someGroup" value="#{myBean.selectedItem}"> <f:selectItems value="#{myBean.selectItems}" /> </h:selectOneRadio> <h:selectOneRadio id="radio1" group="someGroup" /> <h:selectOneRadio id="radio2" group="someGroup" />In this case attention needs to be paid to which position each component has in the group. The order of this is determined by the order in which components are added to the view, which is basically the order in which components appear in the view from top to bottom.
This position in the group becomes the index in the select items collection as shown in the example above. I.e. the component with id "radio1" is at position 1 in the group "someGroup" and will thus use the select item at index 1 of the collection returned by #{myBean.selectItems}. It's an error if more radio button components are used than available items in the collection, but radio buttons don't all have to share the same collection. Each button can be given an individual item, from an EL binding or via a static value. The latter is demonstrated below:
<h:selectOneRadio id="radio0" group="someGroup" value="#{myBean.selectedItem}"> <f:selectItems value="#{myBean.selectItems}" /> </h:selectOneRadio> <h:selectOneRadio id="radio1" group="someGroup" itemValue="staticValue" /> <h:selectOneRadio id="radio2" group="someGroup" />In the example shown above the 2nd element (index 1) of the collection will be overridden by the value "staticValue". If the last buttons are given their own values the collection can be smaller than the total number of buttons in a group. I.e. in the above example, if "radio2" was given a static value the collection returned by #{myBean.selectItems} would only have to have 2 elements.
styleClass attribute on h:column (spec issue 217)
Another omission in JSF that has been missed by JSF developers since the dawn of time is somewhat more control over the styling offered by the build-in h:dataTable component. One problem is with the styleClasses attribute that applies a series of styles round robin to the columns it contains, but doesn't make it possible to set a specific style on an individual column.
A large amount of third party tables from component libraries such as RichFaces and Tomahawk filled this void, but for such a simple and basic thing it's curious that the core dataTable component doesn't offer this.
Now a little over 10 years after an issue for this was filed, JSF 2.3 finally brings us the styleClasses attribute on an individual dataTable column. The following shows an example of this:
<h:dataTable value="#{someBean.somelist}" var="item" > <h:column>#{item}</h:column> <h:column styleClass="foo">#{item}</h:column> </h:dataTable>With someBean.somelist being a List containing the strings "a" and "b", this would be rendered as something like the following:
<table> <tbody> <tr> <td>a</td> <td class="foo">a</td> </tr> <tr> <td>b</td> <td class="foo">b</td> </tr> </tbody> </table>
rowClass attribute on h:dataTable (spec issue 217)
The h:dataTable component features a rowClasses attribute that applies a series of styles round robin to the rows that are being rendered. This however does not allow EL access to the current row being rendered.
JSF 2.3 therefor introduces a new attribute, aptly named rowClass that does allow access to the current row from EL. The following shows an example of this:
<h:dataTable value="#{someBean.someList}" var="item" rowClass="#{item == 'b'? 'foo' : ''}" > <h:column>#{item}</h:column> </h:dataTable>With someBean.somelist being a List containing the strings "a" and "b", this would be rendered as something like the following:
<table> <tbody> <tr class=""> <td>a</td> </tr> <tr class="foo"> <td>b</td> </tr> </tbody> </table>
Iteration in UIRepeat without backing model (spec issue 1102)
In JSF there are 2 main constructs for basic iterating; the JSTL derived <c:forEach> tag and the <ui:repeat> component. The main difference is that the first is a build-time component while the latter is render-time component. This means <c:forEach> is not a component itself but is capable of adding components to the component tree while <ui:repeat> is a single component that iteratively generates its output (e.g HTML).
Another difference is that <c:forEach> has a begin and end attribute that can be used for an arbitrary iteration (like in java a regular for loop), while <ui:repeat> only iterates over a collection bound to the value attribute (which is more like an enhanced for loop or stream in java).
In JSF 2.2 and before you can thus not trivially do an arbitrary iteration without a backing model (collection) during render-time. JSF 2.3 will therefor introduce support for the <c:forEach> style iteration in <ui:repeat> using attributes of the same name. The following gives an example:
<ui:repeat begin="0" end="10" step="2" var="i"> #{i} </ui:repeat>The above will render the sequence 0, 2, 4, 6, 8 and 10. Note that the begin and end attributes are both inclusive, and the step attribute is optional (it'll default to 1).
Automatic conversion in UISelectMany for Collection (spec issue 1422)
The UISelectMany component (which backs e.g. the <h:selectManyMenu> tag) has an eleborate algorithm for determining how multiple values that are posted back from an HTML <select> element are converted.
The difficulty here is that contrary to converting a single value, the component primarily sees an array or a Collection as the target to store converted values in. Arrays have a non-erased element type in Java, but due to the way generics are implemented it's not always possible and certainly not easy to retrieve the generic type (and thus element type) of a Collection. Because of this, the automatic by-type conversion that JSF normally does in absence of an explicit converter was not supported when the UISelectMany component was bound to a Collection.
As the OmniFaces' SelectItemsConverter has been showing for some time it's possible to do automatic conversion from String to an object in another way. Namely, by first mapping which String value was generated for each object instance, and then using the submitted string value(s) as key to map back.
E.g. suppose we have the collection of objects {Object1, Object2, Object3} generated by select items which are initially converted to String values {"a", "b", "c"}. Each of those then become the value of the value attribute in the HTML <option> element. Now when the user posts back {"a", "c"}, the conversion from object to String is performed again in the same way as during the initial rendering (in absence of an explicit converter this means it will use a by-type converter for each non-nul, non-string object instance), but now also mapped. So, we get a map of {"a" → Object1, "b" → Object2, "c" → Object3}. We can then use this map to automatically convert "a" to Object1, and "c" to Object3.
Do note that this does require that the same select items are available before and after the postback, but this is already a requirement in JSF (so that JSF can check that only values are posted back that were also initially rendered).
In JSF 2.3 exactly this technique will now be used to automatically convert values that are posted back for a UISelectMany component that's bound to a Collection.
(Since this type of automatic conversion is also convenient for other situations it's being considered to optionally apply this same technique elsewhere as well)
The following shows an example:
On a view within a form:
<h:selectManyCheckbox value="#{myBean.selectedItems}"> <f:selectItems value="#{myBean.allItems}" /> </h:selectManyCheckbox>
Java backing bean:
@Model public class MyBean { public static enum Item { A, B, C; } private List<Item> selectedItems; public List<Item> getAllItems() { return asList(Item.values()); } public List<Item> getSelectedItems() { return selectedItems; } public void setSelectedItems(List<Item> selectedItems) { this.selectedItems = selectedItems; } }When the <h:selectManyCheckbox> shown above is posted back, selectedItems will contain a list with the enum instances of type Item corresponding to the selection that was made, without requiring the use of an explicit converter.
Importing constants into EL namespace (spec issue 1424)
Using the EL language a view in JSF 2.2 and earlier can make references to @Named beans and to a number of implicit objects. Constants such as enums and final static fields are not that easy to reference; they can't be easily @Named and they typically live in a class of which there's no instance and even if there is doesn't have getters for them.
Yet, such constants are often needed on a view for diverse things such as the values of a color or country selector.
The typical solution in JSF is then to have some bean return those, either directly or by first converting them into a Map or List of some kind. Because this is a somewhat tedious and often recurring task, utility libraries such as OmniFaces and PrimeFaces extensions have provided several solutions for this. EL 3.0 basically supports this too, but actually using it on a view only works in JSP.
JSF 2.3 will introduce support for using constants on a Facelets view via the new <f:importConstants> tag which is backed by the UIImportConstants component.
Using this tag, all constants of a given fully qualified type will be inserted in the application scope as a Map using the simple name of that type, or optionally a user specified name.
For instance consider the class MyClass as given below:
package mypackage; public class MyClass public static final String CONSTANT1 = "constant1" public static final String CONSTANT2 = "constant2" }Importing this via the <f:importConstants> tag will cause a Map to be created with entries {"CONSTANT1" → "constant1", "CONSTANT2" → "constant2"}, which will be put in application scope using the name MyClass.
Because a Map is made available, there's a simple handle to all values, as well as to an individual constant.
The following shows an example of importing the class given above on a Facelet. Note that the tag has to be placed in the metadata section.
On a view:
<f:metadata> <f:importConstants type="mypackage.MyClass" /> </f:metadata>After this import declaration, an individual constant can be accessed as follows:
#{MyClass.CONSTANT1}The above will print "constant1" (without the quotes).
Iterating over all constants can be done as follows:
<ui:repeat var="entry" value="#{MyClass}"> Key: #{entry.key} Value: #{entry.value} </ui:repeat>The above will print "Key: CONSTANT1 Value: constant1 Key: CONSTANT2 Value: constant2" (without the quotes).
Besides the class shown above, importing also works for interfaces and enums, and for the static inner class versions of those.
Official spec recognition for dynamic component tree manipulation (spec issue 1007)
JSF has supported the concept of dynamic component tree manipulation for a long time. Dynamic component tree manipulation here means that the component tree as it's created by the ViewDeclaratioLanguage is afterwards manipulated via (typically) application code.
Such tree manipulation is quite comparable to manipulating a browser's DOM via e.g. JavaScript.
While modifying the DOM is quite popular and generally well documented, the JSF version is by far not as well known and remains a somewhat obscure technique. Part of the reason this is the case is that few manuals or books mention it and the spec in fact doesn't mention it at all. It therefor took a considerable amount of time for the community to truly discover what the best place is in JSF from which to do this manipulation. A few libraries such as OmniFaces build on this somewhat implicit support that JSF provides with higher level utilities.
JSF 2.3 will officially recognise the existence of dynamic component tree manipulation and demand implementations to support it by means of the following text that was added to UIComponent:
Dynamically modifying the component tree can happen at any time, during and after restoring the view, but not during state saving and needs to function properly with respect to rendering and state saving
No API or implementation changes were made for this issue.
Views and Resources
Basic support for exact mapping (extensionless URLs) (spec issue 1260)
As an MVC framework JSF provides a controller that loads views based on the URL with which it is invoked. This is implemented by using a Servlet for the controller (the FacesServlet) that is either prefix or suffix (extension) mapped. The right view route is then obtained by removing the mapping parts from the URL, which is then used as a base name that the view declaration language (VDL, aka templating engine) can use to load the actual physical view.
For instance, if the FacesServlet is mapped to /faces/* and *.jsf, then a URL like "https://example.com/view.jsf", "https://example.com/faces/view.xhtml" or "https://example.com/faces/view" yields the base name "view", which the Facelets VDL can then use to load the file "view.xhtml".
In all cases however there's a certain amount of clutter in the URL, which for some time has been deemed as unwanted. Third party libraries like PrettyFaces and OmniFaces have been providing support for removing this unwanted clutter and allow to have simple SEO friendly URLs in JSF like "https://example.com/view".
Both these libraries need a fair amount of non-trivial code to achieve this, which stems from the fact JSF is natively only aware of prefix and suffix mapping, and thus has to be tricked in thinking either one of these two mappings is used.
In JSF 2.3 this has been partially addressed by adding support for so-called exact mapping to the existing prefix and suffix mapping options. "Partially" here means that unfortunately no out of the box high level support for extensionless URLs has been added, but that JSF has awareness of exact mapping now. This in turn should make it much easier for third party code to implement fully featured extensionless support, but also makes it possible to have basic extensionless URLs in JSF by manually exact mapping the FacesServlet in web.xml one or more times.
The following shows an example of this:
<servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <!-- Suffix/extension mapping --> <url-pattern>*.jsf</url-pattern> <!-- Prefix mapping --> <url-pattern>/faces/*</url-pattern> <!-- Exact mapping, new for JSF 2.3 --> <url-pattern>/foo</url-pattern> <url-pattern>/bar</url-pattern> <url-pattern>/some/kaz</url-pattern> </servlet-mapping>With these mappings in place, and when using the default Facelets VDL, and with files foo.xhtml, bar.xhtml, and some/kaz.xhtml in the root of a .war, and assuming the .war is deployed to the root of a server listening to port 8080 for http traffic, the following URLs can be used to load these 3 different views:
- http://localhost:8080/foo
- http://localhost:8080/bar
- http://localhost:8080/some/kaz
Obtaining list of all view resources (spec issue 1435)
In JSF view resources, which are the files that contain the source code for a view, are abstracted behind the ViewHandler. This ViewHandler interacts with one or more ViewDeclarationLanguage instances, which each represent a specific templating engine (such as Facelets, or JSP). A ViewDeclarationLanguage on its turn may (but doesn't have to) use the ResourceHandler to load the physical file containing the view's source.
This abstraction allows for views to be transparently loaded from multiple locations, such as the filesystem, a jar on the filesystem, a database, from memory, etc without the core JSF runtime having the know about them. Users can add locations by replacing or decorating each of the above mentioned artefacts.
Because of the abstraction it's not really possible to obtain a list of all views, since there's no method on each of those abstracting artefacts that returns such list. By contrast, ServletContext which also represents a small abstraction over loading resources does have such a method.
Therefor JSF 2.3 introduces a series of methods on all these 3 artefacts that does allow one to obtain that list. These methods are roughly modelled after JDK 8's Files#walk, and thus return a Stream that's lazily populated.
The following new methods were added:
Class | Method |
---|---|
ViewHandler | Stream<String> getViews(FacesContext facesContext, String path, ViewVisitOption... options) |
ViewHandler | Stream<String> getViews(FacesContext facesContext, String path, int maxDepth, ViewVisitOption... options) |
ViewDeclarationLanguage | Stream<String> getViews(FacesContext facesContext, String path, ViewVisitOption... options) |
ViewDeclarationLanguage | Stream<String> getViews(FacesContext facesContext, String path, int maxDepth, ViewVisitOption... options) |
ResourceHandler | Stream<String> getViewResources(FacesContext facesContext, String path, ResourceVisitOption... options) |
ResourceHandler | Stream<String> getViewResources(FacesContext facesContext, String path, int maxDepth, ResourceVisitOption... options) |
As can be seen, there's the optional ViewVisitOption for the ViewHandler and ViewDeclarationLanguage methods, and the ResourceVisitOption for the ResourceHandler methods.
ViewVisitOption currently has only one value and that's the somewhat lengthy "RETURN_AS_MINIMAL_IMPLICIT_OUTCOME", which causes views to be returned in their most minimal form such that they can be used as the implicit outcome for e.g. action methods or the outcome attribute of various component tags. In most cases this will be identical to the extensionless form. E.g. "/somepath/foo" instead of "/somepath/foo.xhtml".
ResourceVisitOption only has one value as well and that's "TOP_LEVEL_VIEWS_ONLY", which when provided causes only views to be returned that can be used to serve requests. Without this option views that can be used for e.g. includes will be returned as well.
The following shows an example:
@Inject private FacesContext context; [...] // Views from all VDLs Stream<String> allViews = context.getApplication() .getViewHandler() .getViews(context, "/"); // Views from just the Facelet VDL Stream<String> faceletsViews = context.getApplication() .getViewHandler() .getViewDeclarationLanguage(context, "/foo.xhtml") .getViews(context, "/");
Standardised resource rendered tracking (spec issue 1404 )
JSF 2.0 introduced the resource handler API, which is a framework facility for serving up resources like JavaScript files, style sheets, images and other files in support of components that need them. Before the introduction of this API most component libraries bundled their own solution, like e.g. a Servlet or a Filter.
While JSF 2.0 standardised an API for this, it did not standardise in this API methods to track if a given resource reference (say a link to "jsf.js" from the "javax.faces" library) has already been rendered before and to set that it has been. The two JSF implementations (Mojarra and MyFaces) both do this tracking, but in JSF 2.2 and before they had their own private implementation for this. Being a private implementation means third party libraries like PrimeFaces, OmniFaces, etc could not take advantage of this tracking, and thus could not easily extend this part of the resource API.
In JSF 2.3 tracking whether resource references have been rendered will be standardised via the introduction of two new methods for the ResourceHandler:
- boolean isResourceRendered(FacesContext context, String resourceName, String libraryName)
- void markResourceRendered(FacesContext context, String resourceName, String libraryName)
The two methods are connected to each other in the fact that isResourceRendered for a given resource can only return true when markResourceRendered has been called for that same resource. In other words, implementations *must* call markResourceRendered and *must* check isResourceRendered.
External libraries can therefor safely wrap the ResourceHandler and provide their custom behaviour. Alternatively they can call markResourceRendered on the default ResourceHandler to prevent a given resource reference to be rendered by the framework, i.e. so they can render that resource reference themselves in a custom way (e.g. as part of combining multiple resources into a single one).
(This is a rather advanced feature that the average JSF application developer will not likely come in contact with.)
Resource loading for components dynamically added via ajax (spec issue 1423 )
Since JSF 2.0 components can declare a resource dependency, which will cause the JSF runtime to make sure this resource is provided to the client when the view containing that component is loaded. This happens via the resource handler API by e.g. rendering a link in the head element.
Since the initial versions of JSF it has also been possible to do dynamic component tree manipulation, which basically means programmatically adding a component to the component tree by application code after that tree has been created by the JSF runtime.
Then there's the somewhat related concept of build-time tags in JSP and Facelets based views, which can cause different component trees to be created depending on certain variables. E.g. with the c:if tag a component can be completely eliminated from the tree, which is technically quite different from setting its rendered attribute to false (although the effect on the final rendered output can be quite identical). Includes with a dynamic (EL based) src attribute are also in this category.
Finally, JSF 2.0 added support for AJAX where a partial response is send back by the server that contains directives to only update certain parts of the client side HTML/DOM tree.
As it appeared the combination of these four factors mentioned above didn't play out well; a JSF component with a resource dependency that is dynamically added via either a build-time tag or via dynamic component tree manipulation during an AJAX request (other than for the @all target) failed to have its resource provided. In other words, a component depending on a javascript would not have that javascript added after an ajax request and so would most likely fail.
In JSF 2.3 this problem has been addressed by specifying a simple but effective algorithm that JSF implementations must adhere to. No new API methods were needed for this. That algorithm in simplified wording is:
- After restore state has been done for an AJAX request, all component resources are marked as already rendered (as an AJAX request comes from an existing rendered view that already has al its resources)
- In render response if the AJAX request is not for updating @all, all component resources that are NOT marked as already rendered (which thus must be the newly added components) are put in the update section of the partial-response that's send to the client with a new identifier javax.faces.Resource
- The "jsf.js" script has to append every element from the update section with this new javax.faces.Resource identifier to the head of the HTML document, if that element is not already there
Note that via the condition "if that element is not already there" in the above algorithm the "jsf.js" script now takes upon it a part of deduplicating resource references, a task that was previously done solely server side.
Type-safety
Generics for ExternalContext#getInitParamterMap (spec issue 1382)
Quite a number of types in JSF originate from before generics were available in Java. In subsequent releases Java 5 was targeted and existing types and methods were extended with generic parameters.
One of the methods that was missed before is ExternalContext#getInitParamterMap, which returns a raw Map in JSF 2.2 and earlier.
In JSF 2.3 this has been corrected and ExternalContext.html#getInitParameterMap now returns a Map<String, String>.
Generics for Converter and Validator interfaces (spec issue 1355)
Both the Converter and Validator interfaces in JSF take an Object as their input value. Implementations then typically demand that this Object is of a specific type and that otherwise an exception should be thrown.
This contract predates generics and instead of demanding such type constraint via JavaDoc one can far better express this via a generic parameter. In JSF 2.3 both interfaces have now been parameterized and implementations can concisely define the exact input type, and in case of the Converter interface additionally the exact return type.
This updated interfaces are shown below:
public interface Converter<T> { T getAsObject(FacesContext context, UIComponent component, String value); String getAsString(FacesContext context, UIComponent component, T value); }
public interface Validator<T> { void validate(FacesContext context, UIComponent component, T value); }
Note that the myriad of existing Converter and Validator implementations in JSF have not been parameterized and are raw types. The reason for this is backwards compatibility.
E.g. in some obscure but possible cases code could actually depend on passing an Object to some Converter implementation. Even when such Object could only be of say type Foo, then actually typing the constructor as accepting only Foo will not compile anymore. A variety of other even more obscure but theoretical possible incompatibilities were discovered as well. One could ask how generics can ever have been introduced in the JDK itself for existing types, but even there some compromises were made (like the infamous Map#get taking an Object as input instead of the generic parameter for the key).
New converters and validators can of course take advantage of the new generic parameters, but existing ones in JSF have been frozen in time and can never change.
Constants for "jsf.js", "javax.faces" and postback parameters (spec issue 1428)
The JSF spec defines a javascript with the name "jsf.js" which is served by JSF implementations and contains functions such as the ajax handler. The spec also defines this script is in the "javax.faces" library.
Despite these two names being effectively spec mandated constants, there wasn't an actual constant in code defined for those, and both the RI implementation as well as various libraries were using the non type-safe strings everywhere.
Likewise, a couple of spec defined request parameter names for postback parameters did not have any constants for them defined either.
JSF 2.3 will therefor introduce several new constants as shown in the table below:
Fully qualified name | Value | Description |
---|---|---|
javax.faces.application.ResourceHandler.JSF_SCRIPT_RESOURCE_NAME | "jsf.js" | Resource name of JSF script resource |
javax.faces.application.ResourceHandler.JSF_SCRIPT_LIBRARY_NAME | "javax.faces" | Library name of JSF script resource |
javax.faces.component.behavior.ClientBehaviorContext.BEHAVIOR_SOURCE_PARAM_NAME | "javax.faces.source" | The request parameter name whose request parameter value identifies the source component of behavior event |
javax.faces.component.behavior.ClientBehaviorContext.BEHAVIOR_EVENT_PARAM_NAME | "javax.faces.behavior.event" | The request parameter name whose request parameter value identifies the type of behavior event |
javax.faces.context.PartialViewContext.PARTIAL_EVENT_PARAM_NAME | "javax.faces.partial.event" | The request parameter name whose request parameter value identifies the type of partial event |
The RI implementation has been updated to use these new constants.
Configuration
Facelets default to non-hot reload in production (spec issue 936)
JSF has the ability to cache Facelets. Caching here means that the result of the XML parsing and compilation step is kept in memory, e.g. Facelets will not read the XML from disk at every request and will not reparse that XML either. (it will however still do the composition of includes and templates at every request)
While the default is not specified, the RI (Mojarra) uses a default of 2 seconds before it looks on disk again if the source file has changed or not. There is a setting to control this default, namely the javax.faces.FACELETS_REFRESH_PERIOD context parameter in web.xml. For example, the following sets a timeout of 10 seconds:
<context-param> <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name> <param-value>10</param-value> <!-- Cache for 10 seconds --> </context-param>
There are two special values; -1 means no refresh (cache indefinitely), while 0 means no caching at all (always hot reload).
For production usage there really is only 1 sensible value, and that's -1, as the Facelets source files will of course not change during production.
JSF 2.0 introduced a setting to indicate the stage its in, which includes the Production stage.
JSF 2.3 now finally adds one and one together and defines that when the project stage is Production (which incidentally is the default stage) the Facelets refresh period is -1 (no refresh).
.xhtml added to default mappings (spec issue 1434)
It's customary in JSF to map the so-called FacesServlet, which acts as the default controller, explicitly to some pattern in web.xml, e.g.
<servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.xhtml</url-pattern> </servlet-mapping>
JSF is however also capable of automatically mapping the FacesServlet, which happens when either a WEB-INF/faces-config.xml is found, or if the application contains a class annotated with- or using any of a number of JSF specific types (such as the new @FacesConfig or previously @ManagedBean).
Unfortunately, when automatically mapped, the mapping is only to /faces/*, *.jsf and *.faces. Since Facelets is overwhelmingly used as the default and only VDL in JSF applications, and those happen to default to the .xhtml extension, a mapping to *.xhtml is in practice the much preferred mapping (apart from an extensionless mapping, which is another story). A .xhtml to .xhtml mapping not only makes it initially easier to understand which file is used for handling a request, but more importantly it also makes an application more secure. Without such mapping in place and without any other measures (like some security constraint), it's possible to request the source of the Facelets file. Depending on how the application is build, and perhaps depending on any comments in the file, this could be a serious risk.
Therefor, JSF 2.3 will add *.xhtml to the list of automatic mappings. Note that this will *only* be used when no explicit mapping in e.g. web.xml is present. When such mapping is present and no *.xhtml mapping is done manually, the application may still be vulnerable.
The new mapping can be disabled using a context parameter in web.xml as follows:
<context-param> <param-name>javax.faces.DISABLE_FACESSERVLET_TO_XHTML</param-name> <param-value>true</param-name> </context-param>