OmniFaces 2.4 has been released!
This version has relatively few new additions, only one brand new tag <o:url>
which revives good 'ol JSTL <c:url>
for Facelets, and a few utility methods/functions. There are several enhancements and bugfixes in existing stuff, such as the @Param
finally supporting injecting multi-valued parameters such as foo=bar1&foo=bar2
into a String[]
or List<String>
and injecting into primitive type fields. Those few utility methods and enhancements must further simplify logging of JSF (ajax) actions, exceptions and JavaScript errors.
You can find the complete list of additions, changes and fixes at What's new in OmniFaces 2.4? list in showcase.
Installation
Non-Maven users: download OmniFaces 2.4 JAR and drop it in /WEB-INF/lib
the usual way, replacing the older version if any.
Maven users: use <version>2.4</version>
.
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>2.4</version>
</dependency>
For users who don't want to use CDI, there's the CDI-less 1.14 with all 2.4 enhancements and fixes (but no brand new 2.x additions nor the o:url!).
Good ol' JSTL <c:url> revived
Sometimes there's need to access and/or print the current request URL "plain vanilla" in a JSF page. Common use cases are to prepopulate a ?from=
request parameter for the login form so it can figure out where to redirect back after a successful login, and filling the HTML5 link relations referring the current or another page on the same site. Previously, this could to some extent (no control over domains) be done with JSTL ><c:url>
which was removed in Facelets.
This has now been revived in OmniFaces 2.4 as <o:url>
and even further enhanced. It supports setting the (relative) domain via domain
attribute and it supports the same includeViewParams
, includeRequestParams
and useRequestURI
attributes as <o:form>
. The <o:url>
also supports the var
attribute allowing to set the value as an EL variable which can in turn be used in an EL expression elsewhere in the page.
Here's an example:
<o:url var="currentURL" />
...
<h:head>
...
<link rel="canonical" href="#{currentURL}" />
...
</h:head>
<h:body>
...
<h:link value="Login" outcome="login">
<f:param name="from" value="#{currentURL}" />
</h:link>
...
</h:body>
@Param now supports multiple values and primitives
The CDI @Param
annotation has in OmniFaces 2.4 been further improved to also support injecting multi-valued request parameters such as foo=value1&foo=value2&foo=value3
into an array or List
.
@Inject @Param(name="foo")
private List<String> foos;
@Inject @Param(name="bar")
private String[] bars;
Conversion and validation is also supported on multi-valued parameters like as already supported on single-valued parameters. On multi-valued parameters, JSF native conversion and validation will run on each submitted value. Bean Validation, if any, will however be performed on the entire List
or array property and not on each individual item.
Furthermore, the @Param
now also supports injecting into a primitive field. Previously this wasn't possible because CDI would attempt to inject an empty value as null
into the field, which would only throw an exception (no autoboxing magic there in reflection). The @Param
will now automatically take care about injecting the right default value of the primitive field in case the value is absent or empty.
Logging made easier
OmniFaces 2.4 comes with several utilities and enhancements which should further simplify logging of (ajax) actions, exceptions and JavaScript errors.
First, the Components
got two new utility methods, one to find out the source component of the (ajax) form submit and another to extract all actions and listeners from it as a list of EL expression strings such as #{bean.action}, #{bean.actionListener}, #{bean.ajaxListener}
.
UIComponent actionSource = Components.getCurrentActionSource();
List<String> actionExpressions = Components.getActionExpressionsAndListeners(actionSource);
// ...
This also works for e.g. <h:inputText><f:ajax listener="#{bean.listener}">
. You can find a concrete example as PhaseListener
in my answer to How can I log method expressions of JSF ajax requests.
Second, the FullAjaxExceptionHandler
got a new logException
overloaded method with a LogReason
enum argument which should help in determining when exactly the exception has been caught and whether it was successfully handled or not. For example, if handling has failed because the response was already committed, or the error page itself contained an error, then you could take additional action by sending an email to site admin.
@Override
protected void logException(FacesContext context, Throwable exception, String location, LogReason reason) {
switch(reason) {
case RENDER_EXCEPTION_UNHANDLED:
case ERROR_PAGE_ERROR:
yourMethodToSendAnEmailToAdmin(exception, reason);
break;
default:
super.logException(context, exception, location, reason);
}
}
Third, the CombinedResourceHandler
and <o:deferredScript>
have been altered to always render crossorigin="anonymous"
attribute to the generated <script>
element. This will basically enable JavaScript error logging via window.onerror
on scripts possibly served via a CDN. Such a logger can look like below, with little help of jQuery and a servlet:
$(window).on("error", function(message, source, line, column, error) {
try {
$.post("/script-error", $.param({
url: window.location.href,
client: navigator.userAgent,
message: message,
source: source,
line: line,
column: column,
error: error ? error.stack : null
}));
}
catch(e) {
// Ignore.
}
});
@WebServlet("/script-error")
public class ScriptErrorServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String url = request.getParameter("url");
String client = request.getParameter("client");
String message = request.getParameter("message");
String source = request.getParameter("source");
String line = request.getParameter("line");
String column = request.getParameter("column");
String error = request.getParameter("error");
// ...
}
}
Noted should be that the detail of the information being sent depends on the client used. Chrome for example is very kind to include the full stack trace
More OmniFaces in upcoming JSF 2.3
Besides the new JSF 2.3 <f:websocket>
, which is largely based on <o:socket>
introduced in previous OmniFaces version, more OmniFaces solutions have been integrated into upcoming JSF 2.3 the last months. The FixViewState
is now in standard jsf.js
as per spec issue 790, the <o:commandScript>
is integrated as new JSF 2.3 <h:commandScript>
as per spec issue 613, and the <o:importConstants>
is integrated as new JSF 2.3 <f:importConstants>
as per spec issue 1424 (which should be declared inside <f:metadata>
). Those OmniFaces artifacts will be deprecated as per upcoming OmniFaces 3.0 for JSF 2.3.
Maven download stats
Here are the Maven download stats after previous release:
- April 2016: 8050
- May 2016: 8590
- June 2016: 8560