Search code examples
jsfjsf-2jettyfacelets

How to load JSF / facelets library from a common directory?


We have a number of webapps that all use a certain JSF library. We'd like to place the library in a common location or on the main classpath. The trouble is that the system expects the library to be in WEB-INF/lib so the webapp classloader can scan it and load it.

We are the creators of this particular library, and during development it's way easier to have it on the main classpath.

Is this possible? Can anyone give an example of what to put in web.xml to make this happen (if that's the right mechanism)?


Solution

  • We are the creators of this particular library, and during development it's way easier to have it on the main classpath. Is this possible?

    For Facelets resources this is possible with a custom ResourceResolver in webapp itself.

    public class FaceletsResourceResolver extends ResourceResolver {
    
        private ResourceResolver parent;
        private String basePath;
    
        public FaceletsResourceResolver(ResourceResolver parent) {
            this.parent = parent;
            this.basePath = "META-INF/resources"; // TODO: Make configureable?
        }
    
        @Override
        public URL resolveUrl(String path) {
            URL url = parent.resolveUrl(path); // Resolves from WAR which would also do META-INF/resources of JARs in WAR.
    
            if (url == null) {
                url = getClass().getResource("/" + basePath + path); // Resolves from JARs in WAR when base path is not META-INF/resources.
            }
    
            if (url == null) {
                url = Thread.currentThread().getContextClassLoader().getResource(basePath + path); // Resolves also from anywhere else in classpath.
            }
    
            return url;
        }
    
    }
    

    To get it to run, configure it as follows in webapp's web.xml:

    <context-param>
        <param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
        <param-value>com.example.FaceletsResourceResolver</param-value>
    </context-param>
    

    For annotated JSF artifacts like managed beans, etc which needs to be scanned by the JSF annotation scanner, this is not possible. The JAR has really to end up in /WEB-INF/lib. See also How to reference JSF managed beans which are provided in a JAR file?