Override ui: insert and ui: include-Handler
There are many other topics on how to override an existing render in JSF. They all lead to one entry in faces-config. You "need" only component-family
, renderer-type
, render-kit-id
and your implementation inrenderer-class
I understand and can reproduce all of these examples, but in my particular case, I would like to override the behavior <ui:include>
and <ui:insert>
. Unfortunately, I cannot find out what values I need to include in the attributes mentioned above, because the file is ui:taglib.xml
not as verbose as the other tags.
Do you have any idea how to override them?
Edit: BalusC mentioned another section , it uses custom tags like <my:include>
or <my:insert>
, but that I don't want to use. If I did, I had to refactor all of my existing code and my future code won't work without using my custom taglib.
I would like to hook into the render <ui:include>
and <ui:insert>
so that I can reuse the plugin I am about to develop without modifying any existing code.
source to share
... without changing any existing code
You can not. At least without being closely related to a specific implementation (Mojarra or MyFaces). An alternative would be to bite the bullet and replace all <ui:include>
, and <ui:define>
on <my:include>
and <my:define>
. Faces are not yet fully abstracted / standardized in the JSF spec. There's only the Facelet factory cache , but not the Facelet factory context, otherwise it would be easy. As a rule of thumb, forget about customizing your tags in an <ui:xxx>
abstract way. You will need to hack the implementation.
Considering you are using Mojarra 2.1.19, you need to copypaste it com.sun.faces.facelets.impl.DefaultFaceletContext
into your web application project while maintaining it com.sun.faces.facelets.impl
. Classes in WAR have higher priority on loading than in WAR /WEB-INF/lib
and server /lib
. So this one in your WAR will be used instead.
Given that you would like to achieve the same as in Customize ui: enable rendering to add prefix / postfix on <ui:include>
and <ui:define>
:
Example, suppose an empty .xhtml file:
Input
<ui:include src="file.xhtml" />
Output
<!-- START file.xhtml --> <!-- END file.xhtml -->
Here's how you can achieve this by editing the: copypasted class:
-
Add a helper method to the class that creates the comment component (which is just a simple text output component).
private static UIComponent createComment(String comment) { UIOutput text = new UIOutput(); text.setValue("\n<!-- " + comment + " -->\n"); return text; }
-
Extend the oneliner method
includeFacelet(UIComponent, String)
on line 199 as shown below:parent.getChildren().add(createComment("START INCLUDE " + relativePath)); facelet.include(this, parent, relativePath); parent.getChildren().add(createComment("END INCLUDE " + relativePath));
-
Expand
includeDefinition(UIComponent, String)
around line 366 withclient.apply(this, parent, name)
as shown below:int start = parent.getChildCount(); found = client.apply(this, parent, name); if (found) { parent.getChildren().add(start, createComment("START DEFINE " + name)); parent.getChildren().add(createComment("END DEFINE " + name)); }
During testing, however, I found a caveat. I have an HTML template <title>
as shown below:
<h:head>
<title><ui:insert name="title">#{view.viewId}</ui:insert></title>
</h:head>
This way, the comments also end up inside the element <title>
. Unfortunately, comments in the HTML header are not valid syntax (only PCDATA
allowed) and they are interpreted literally and thus appear in the document title. You might want to create a blacklist based on the name
definition, or maybe parent
.
source to share