OmniFaces 3.0 has been released!
The minimum requirements have been upgraded from Java 1.7, JSF 2.2, EL 2.2, Servlet 3.0, CDI 1.1 and (optional) BV 1.1 to Java 1.8, JSF 2.3, EL 3.0, Servlet 3.1, CDI 2.0 and (optional) BV 2.0. WebSocket 1.1 hasn't been upgraded since, so it's still the same. As of now, OmniFaces 3.0 is technically still backwards compatible with EL 2.2, CDI 1.1 and BV 1.1, as features in newer versions are still unutilized, but that may change in a future 3.x version. OmniFaces 3.0 will explicitly prevent deployment when Java 1.8, JSF 2.3 or CDI 1.1 are absent in the environment.
To learn what's new in JSF 2.3, head to the complete overview of new JSF 2.3 features in Arjan Tijms' blog.
As shown in what's new in OmniFaces 3.0 at the showcase site, below is a summary of breaking changes, new things and deprecated things in OmniFaces 3.0 as compared to OmniFaces 2.6.8, which is also released today.
Breaking changes:
<o:form useRequestURI="true">
is now the default behavior of<o:form>
as it was basically the main reason to use<o:form>
. I.e. it will always submit to exactly the same URL as in browser's address bar whereas the<h:form>
only submits to the forwarded URL without query string, causing among others view parameters and path parameters to get lost every time. You can if necessary disable this by<o:form useRequestURI="false">
or switching back to<h:form>
.<o:form>
will now by default perform a partial submit on any JSF ajax request. In other words, only the parameters actually covered byexecute
attribute of<f:ajax>
will be sent, hereby reducing the request payload to not contain unnecessary parameters. This is similar to PrimeFacespartialSubmit
feature. Even though this has proven to work flawlessly in PrimeFaces for ages, you can if necessary disable this by<o:form partialSubmit="false">
.<o:validateBean showMessageFor="@violating">
will not anymore show the "remaining" messages (coming from other bean properties which are not covered by the JSF form) as a global message but just suppress them.ValidateMultipleFields
(all multi-field validators basically) have previously skipped all disabled/readonly/nonrendered inputs. Now they won't anymore be skipped, and thevalues
argument (3rd argument of validate method) will contain their current model value (and thus not the submitted value).- Package
org.omnifaces.component.output.cache
has been migrated toorg.omnifaces.util.cache
and several previously private/hidden artifacts have been made public, so that it's now more useful for non-component related caches. - All
Faces
/FacesLocal
/Components
/Servlets
methods which previously threwIOException
will now throw Java8'sjava.io.UncheckedIOException
instead, hereby reducing down unnecessarythrows IOException
boilerplate in methods because those should always be bubbled up into the container. org.omnifaces.facesviews.FacesServletDispatchMethod
andViewHandlerMode
which was deprecated since 2.6 have now been removed without replacement (as they have become superfluous since Servlet 3.0).org.omnifaces.renderkit.Html5RenderKit
which was deprecated since 2.2 has now been removed without replacement (as this has become superfluous since JSF 2.2 with new passthrough attribtue feature).org.omnifaces.config.BeanManager
which was deprecated since 2.5 has now been removed withorg.omnifaces.util.Beans
as replacement.- RichFaces targeted hacks have been removed. OmniFaces 3.0 is therefore not anymore compatible with RichFaces. Note that RichFaces itself was declared "End of Life" June 2016 and is already not compatible with JSF 2.3.
New things:
<o:selectItemGroups>
has been added which should remove the need to manually bakeSelectItemGroup/SelectItem[]
instances in beans as there's (still) no corresponding tag in standard JSF for this.<o:url>
has been extended with avalue
attribute which can take an arbitrary/external URL.omnifaces.ImplicitNumberConverter
which extends<f:convertNumber>
, but doesn't annoyingly require enduser to explicitly input the percent or currency symbol when usingtype="percent"
ortype="currency"
.org.omnifaces.eventlistener.FacesRequestLogger
phase listener is introduced which will print detailed logs of JSF requests, including request method/URI/params, session/viewstate ID, remote user, action method expressions, faces messages and phase timings.Faces#getRequestAttribute()/getFlashAttribute()/getViewAttribute()/getSessionAttribute()/getApplicationAttrubute()
got an overload which takes a new argument representing the supplier which will be computed in case the attribute is absent.Faces#isRequestSecure()
/Servlets#isSecure()
has been added which also checks the de-factoX-Forwarded-Proto
header which returns the protocol as obtained by the proxy. Useful in case the server runs HTTP but proxy runs HTTPS.#{of:isInstance('com.example.ClassName', object)}
has been added to act asinstanceof
in EL.#{of:parenthesize(object)}
has been added which will print parenthesis around the given object only and only if it isn't null nor empty nor equals zero.NoAutoGeneratedIdViewHandler
will now also recognizeprependId="false"
and log a warning because this is bad practice.- Under the covers, many things are replaced by new JSF 2.3 API things (among others, a bunch of new constants, improved faces wrappers and
ResourceHandler#markResourceRendered() / isResourceRendered()
) and also Java8 lambdas and streams have been introduced where possible.
Deprecated things:
<o:commandScript>
has been deprecated as it's now moved into JSF 2.3 as<h:commandScript>
with exactly the same functionality.fixviewstate.js
has been deprecated as it's now finally solved in JSF 2.3 (by yours truly).<o:form includeViewParams="true">
as well as<o:form includeRequestParams="true">
have been deprecated as those have never proven to be more useful thanuseRequestURI="true"
.
Noted should be that the <o:socket>
is also moved into JSF 2.3 as <f:websocket>
with here and there a few small API generifications. But this won't be deprecated anywhere in OmniFaces 3.x as it still has room for new ideas and improvements.
As to new things, the benefits of <o:selectItemGroups>
, omnifaces.ImplicitNumberConverter
and Faces#getXxxAttribute()
overloads are detailed below.
Not anymore explicitly creating new SelectItemGroup()
When grouping select item options in a <optgroup>
, you had to manually bake SelectItemGroup
instances yourself. Assuming that you have List<Category>
as wherein Category
in turn has a List<Product>
:
private Product selectedProduct;
private List<SelectItem> categories;
@Inject
private ProductService productService;
@PostConstruct
public void init() {
categories = productService.listCategories().stream().map(category -> {
SelectItemGroup group = new SelectItemGroup(category.getName());
group.setSelectItems(category.getProducts().stream()
.map(product -> new SelectItem(product, product.getName()))
.toArray(SelectItem[]::new));
return group;
}).collect(Collectors.toList());
}
<h:selectOneMenu value="#{bean.selectedProduct}" converter="omnifaces.SelectItemsConverter">
<f:selectItem itemValue="#{null}" />
<f:selectItems value="#{bean.categories}" />
</h:selectOneMenu>
This is too much JSF 1.0. Even in JSF 2.3, there's still nothing like <f:selectItemGroups>
. OmniFaces 3.0 therefore brings a <o:selectItemGroups>
into the game.
private Product selectedProduct;
private List<Category> categories;
@Inject
private ProductService productService;
@PostConstruct
public void init() {
categories = productService.listCategories();
}
<h:selectOneMenu value="#{bean.selectedProduct}" converter="omnifaces.SelectItemsConverter">
<f:selectItem itemValue="#{null}" />
<o:selectItemGroups value="#{bean.categories}" var="category" itemLabel="#{category.name}">
<f:selectItems value="#{category.products}" var="product" itemLabel="#{product.name}" />
</o:selectItemGroups>
</h:selectOneMenu>
Not anymore explicitly entering $ or %
Sometimes you need to have the enduser to input currencies. For that, you'd intuitively use <f:convertNumber type="currency">
.
<h:outputLabel for="price" value="Price $" />
<h:inputText id="price" value="#{bean.price}">
<f:convertNumber type="currency" currencySymbol="$" />
</h:inputText>
<h:message for="price" />
However, this would surprisingly fail with a conversion error when the enduser doesn't explicitly specify the currency symbol in the input field.
Price $
'12.34' could not be understood as a currency value. Example: $99.99
Of course you could work around it by replacing type="currency"
with pattern="#,##0.00"
. But this is embarrassingly harder to remember than just type="currency"
and even prone to locale-specific differences. In some locales the fractions are optional or even omitted. And what if the enduser thought to enter the currency symbol anyway?
With the new omnifaces.ImplicitNumberConverter
you don't need to worry about this all.
<h:outputLabel for="price" value="Price $" />
<h:inputText id="price" value="#{bean.price}">
<o:converter converterId="omnifaces.ImplicitNumberConverter" type="currency" currencySymbol="$" />
</h:inputText>
<h:message for="price" />
Entering the currency symbol has now become optional and it will be inferred when absent. On outputting, it will be hidden from the output and it will be assumed that the user interface already covers this. The same facility is also available for type="percent"
.
Not anymore explicitly checking if scoped attribute exists
You might have repeatedly stumbled into the below use case in some non-managed JSF artifact (where you'd otherwise of course just have used CDI):
public SomeObject getSomeObject() {
SomeObject someObject = Faces.getRequestAttribute(SomeObject.class.getName());
if (someObject == null) {
someObject = new SomeObject();
Faces.setRequestAttribute(SomeObject.class.getName(), someObject);
}
return someObject;
}
The getRequest/
methods have now all an overload which takes a Supplier<T>
. The usage is now much like Map#computeIfAbsent()
.
public SomeObject getSomeObject() {
return Faces.getRequestAttribute(SomeObject.class.getName(), SomeObject::new);
}
Not anymore explicitly rethrowing IOException
Some utility methods in Faces
throw IOException
when something fails during handling the HTTP response. Generally this is unavoidable, such as end user facing a local network error. Those exceptions are documented to be rethrown. For example,
@PostConstruct
public void init() throws IOException {
if (someCondition()) {
Faces.redirect("other.xhtml");
}
}
However, redeclaring this everytime is tiresome and moreover, in this specific example it goes against the @PostConstruct
contract as it may actually not throw a checked exception. Weld will even warn about this during webapp startup.
With OmniFaces 3.0, all methods which previously threw IOException
will now throw it as Java 8's new UncheckedIOException
instead. So you can safely strip out any unnecessary throws IOException
coming from Faces/FacesLocal/Servlets
utility methods over all place.
@PostConstruct
public void init() {
if (someCondition()) {
Faces.redirect("other.xhtml");
}
}
Installation
Non-Maven users: download OmniFaces 3.0 JAR and drop it in /WEB-INF/lib
the usual way, replacing the older version if any.
Maven users: use <version>3.0</version>
.
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>3.0</version>
</dependency>
But my server doesn't support JSF 2.3!
Don't panic. I wrote a clean set of installation instructions in Mojarra README. In a nutshell, for Tomcat 8.x you just need to upgrade the JARs and add JSONP API as compared to Mojarra 2.2 (with CDI + BV). For Java EE 7 (e.g. WildFly 8-11.x, Payara 4.x, TomEE 7.x, etc) you need to manually swap out server-provided JARs as instructed in the README.
How about OmniFaces 2.x and 1.1x?
2.x is basically already since 2.6 in maintenance mode. I.e. only bugfix versions will be released. It's currently already at 2.6.8, also released today. As long as you're still on JSF 2.2 with CDI, you can continue using latest 2.6.x, but it won't contain new things introduced in 3.x.
1.1x is basically already since 2.5 in maintenance mode. I.e. only bugfix versions will be released. It's currently still at 1.14.1 (May 2017), featuring the same features as OmniFaces 2.4, but without any JSF 2.2 and CDI things and therefore compatible with CDI-less JSF 2.0/2.1.
Maven download stats
Here are the 2017's Maven download stats
- January 2017: 10889
- February 2017: 12060
- March 2017: 14669
- April 2017: 11999
- May 2017: 12521
- June 2017: 11535
- July 2017: 12197
- August 2017: 13925
- September 2017: 13502
- October 2017: 13080
- November 2017: 14372
- December 2017: 11735