Use Webjars in JSF

When using webjars in jsf like:

<h:outputScript id="angular" library="webjars" name="jquery/2.1.4/jquery.js" target="head"/>

You might notice that the version number of the resource is in the tag. This is an annoyance because every time the version is upgraded, the xhtml pages and @ResourceDependency uses must be updated.

Better is to not include the version number and use a custom resourceResolver.

package com.acme;

import javax.faces.application.Resource;
import javax.faces.application.ResourceHandler;
import javax.faces.application.ResourceHandlerWrapper;

import lombok.extern.log4j.Log4j;

import org.webjars.WebJarAssetLocator;

/**
 * @author milo
 *
 * Add: com.vetmanager.base.WebjarsResourceResolver to faces-config.xml for this to work.
 */
@Log4j
public class WebjarsResourceResolver extends ResourceHandlerWrapper {
    private ResourceHandler wrapped;

    /**
     * @param wrapped - ResourceHandler
     */
    public WebjarsResourceResolver(ResourceHandler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public ResourceHandler getWrapped() {
        return wrapped;
    }

    @Override
    public Resource createResource(String resourceName, String libraryName) {
        log.debug("createResource: '" + libraryName + "', '" + resourceName + "'");

        if ("webjars".equals(libraryName) && !resourceName.contains("/")) {
            WebJarAssetLocator locator = new WebJarAssetLocator();
            String fullPath = locator.getFullPath(resourceName);
            if (fullPath != null) {
                resourceName = fullPath.split(libraryName)[1];
            }
            log.debug("createResource: " + fullPath + " => " + resourceName);
        }
        return super.createResource(resourceName, libraryName);
    }
}

register the resolver in faces-config.xml:

<resource-handler>com.acme.WebjarsResourceResolver</resource-handler>

From now on the resource can be used like:

<h:outputScript id="angular" library="webjars" name="jquery.js" target="head"/>