jsfloadingfaces-config

How to control loading order of multiple JSF library JAR files


Short Version:

If two JSF library jar files both include a custom renderer for the same family and type, is there any way from within the library itself (i.e. not from the containing app) of specifying which one should be used? Something like assigning a priority, with higher ones used in preference to lower ones?

Longer Version:

I'm using Primefaces in a project and trying to override the provided head renderer with my own:

<render-kit>
  <renderer>
    <component-family>javax.faces.Output</component-family>
    <renderer-type>javax.faces.Head</renderer-type>
    <renderer-class>com.example.MyHeadRenderer</renderer-class>
  </renderer>
</render-kit>

If I put that into the WEB-INF/faces-config.xml of the war file then it's all good, and my renderer gets used.

However, if I try to deploy my code as part of a library jar (my-utils.jar), with the renderer defined in META-INF/faces-config.xml, then the Primefaces one is used. This contains exactly the same definition, so I'm guessing it just depends on the order they get loaded. Indeed, renaming my library to "xx-comps.jar" works, so it would appear that JSF is loading faces-config.xml files from all jar files in alphabetical order, with later entries just overwriting earlier ones.

Is there any way of forcing the selection to my library?

So far, I have these options:

  1. Put my renderer directly into the WEB-INF/faces-config.xml of the war.
  2. Build a custom Primefaces jar with that one renderer definition removed.
  3. Rename my library and rely on some (undocumented as far as I can see) behaviour from the JSF loader.
  4. Add a custom renderkit which extends the standard one, and reference that from my war WEB-INF/faces-config.xml.

The first three all work but are not ideal, as (1) and (2) require changes outside my library, and (3) just looks dodgy as hell....

The fourth is just an idea as I've never written a render kit before so not aware of the effort involved. No idea if it is practical or would work, but it is better than (1) because at least the application only references a single render kit, and does not need to be updated if/when new renderers are added. Happy to put more effort into researching this approach if it seems a reasonable solution.

Also, I'd ideally prefer to use annotations rather than XML:

@FacesRenderer(componentFamily = "javax.faces.Output", rendererType = "javax.faces.Head")
public class MyHeadRenderer extends Renderer {
  ...
}

Thanks


Solution

  • You can specify the ordering via <ordering> tag in faces-config.xml of the JAR. See also section 11.3.8 of Faces 4.0 specification.

    E.g. if you want your utility library to be loaded after all others, then just do so:

    <ordering>
        <after>
            <others />
        </after>
    </ordering>
    

    If you want to force an explicit ordering, then hook on specifically PrimeFaces, which has a <name>primefaces</name> in its faces-config.xml:

    <ordering>
        <after>
            <name>primefaces</name>
        </after>
    </ordering>
    

    Do note that this <ordering> feature is copied from Servlet-specific web-fragment.xml and in case you also have this file, then you might want to apply the same ordering rules over there. See also section 8.2.2 of Servlet 6.0 specification.

    Real world examples can be found in OmniFaces and OptimusFaces.