Thursday, April 12, 2018

OmniFaces 3.1 adds MessagesKeywordResolver and SourceMapResourceHandler

OmniFaces 3.1 has been released!

Next to a bunch of utility methods, this version adds a MessagesKeywordResolver and a SourceMapResourceHandler. This version also deprecates WebXml.INSTANCE and FacesConfigXml.INSTANCE with as replacement the WebXml.instance() and FacesConfigXml.instance() respectively via an interface instead of an enum. This way they can easier be mocked during unit testing.

You can find the complete list of additions, changes and fixes at What's new in OmniFaces 3.1? list in showcase.

Installation

Non-Maven users: download OmniFaces 3.1 JAR and drop it in /WEB-INF/lib the usual way, replacing the older version if any.

Maven users: use <version>3.1</version>.

<dependency>
    <groupId>org.omnifaces</groupId>
    <artifactId>omnifaces</artifactId>
    <version>3.1</version>
</dependency>

MessagesKeywordResolver

This is the first addition which utilizes a brand new JSF API: the Component Search Expression Framework. The MessagesKeywordResolver basically adds support for @messages in <f:ajax render>.

<h:inputText id="input1" ... />
<h:message id="m_input1" for="input1" />
<h:inputText id="input2" ... />
<h:message id="m_input2" for="input2" />
<h:inputText id="input3" ... />
<h:message id="m_input3" for="input3" />
...
<h:commandButton ... />
    <f:ajax execute="@form" render="@messages" />
</h:commandButton>

This way, only the message components are updated on submit. This is more efficient than e.g. render="@form" which unnecessarily also updates the input and button components.

SourceMapResourceHandler

If you've more than often debugged minified CSS/JS resources in browser developer toolset, you'll probably ever have heard of "source maps", usually referenced by a code comment somewhere in the bottom of the minified file, such as /*# sourceMappingURL=some.js.map */. To the point, these files represent the mapping between the minified version and the unminified version, so that the browser developer toolset can after downloading the source map file automatically unminify the minified version, whereby the original variable names are substituted back.

Very useful, particularly for minified/uglified JS resources. Unfortunately, resolving the source map files doesn't always work well with suffix-mapped JSF resources which uses a virtual URL pattern with /javax.faces.resource/ prefix and .xhtml suffix. The average CSS/JS compiler/minifier also has no knowledge about the way how JSF resources are being served. Fortunately, source map URLs can be set by a SourceMap header on the response of the CSS/JS resource. This is thus exactly what the SourceMapResourceHandler does.

It can be installed in the JSF application by below entry in faces-config.xml:

<application>
    <resource-handler>org.omnifaces.resourcehandler.SourceMapResourceHandler</resource-handler>
</application>

It will by default asusme that the source map files are by the build tool placed in the same folder as the minified resources and have a .map extension appended to the resource name. So it will work when you have a some.js resource and a some.js.map file in the same folder. In case it's by the build tool being placed in a subfolder as in sourcemaps/some.js.map, then you can use the below web.xml context parameter to instruct the SourceMapResourceHandler on this.

<context-param>
    <param-name>org.omnifaces.SOURCE_MAP_RESOURCE_HANDLER_PATTERN</param-name>
    <param-value>sourcemaps/*.map</param-value>
</context-param>

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.9, 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 2018's Maven download stats so far:

  • January 2018: 14646
  • February 2018: 14786
  • March 2018: 18059

Below is the pie of March 2018, 3.0 is already on 9%:

Saturday, April 7, 2018

Do not use org.glassfish Mojarra 2.4.0!

Look, there's a Mojarra 2.4.0 in Maven Central:

What is this? Is JSF 2.4 already there?

No, JSF 2.4 is not there yet. Technically speaking, Mojarra 2.4.0 represents the latest state of the master branch as it was during the transfer from Oracle to Eclipse. That transfer took place when JSF 2.3 specification was already released and JSF 2.4 specification has still to be started yet. JSF 2.4 is far from being a beta, let alone a reasonable snapshot. And yet there is a Mojarra 2.4.0 in Maven instead of e.g. a Mojarra 2.4.0-M1. As per the agreement between Oracle and Eclipse, it was necessary to release the latest work on Mojarra under Oracle's umbrella into Maven Central before the transfer to Eclipse was completed. And later Eclipse will do the same after the transfer is completed so that the integrity can be validated by the public. Using version "2.4.0" is indeed way confusing for the public, but it is what it is.

In other words, you should not use it. A few days later, Mojarra 2.3.4 was also released. Use this instead.

<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.faces</artifactId>
    <version>2.3.4</version>
</dependency>

Technically speaking, Mojarra 2.4.0 is even a step back from Mojarra 2.3.4 as to bugfixes. Mojarra 2.4.0 misses among others the fixes on issues 4274, 4313, 4321, 4324, 4330, 4331, 4332, 4337 and 4358.

After the transfer to Eclipse, we'll as first step change the package name (and thus also the Maven coordinates). We already have a lot of other plans on it. High in our wishlist is removing everything which is @Deprecated and JSP related.

Wednesday, January 3, 2018

OmniFaces 3.0 released!

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 by execute attribute of <f:ajax> will be sent, hereby reducing the request payload to not contain unnecessary parameters. This is similar to PrimeFaces partialSubmit 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 the values 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 to org.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 threw IOException will now throw Java8's java.io.UncheckedIOException instead, hereby reducing down unnecessary throws IOException boilerplate in methods because those should always be bubbled up into the container.
  • org.omnifaces.facesviews.FacesServletDispatchMethod and ViewHandlerMode 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 with org.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:

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 than useRequestURI="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/Flash/View/Session/ApplicationAttribute() 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