How To Create JSF Renderer

JSF Renderer

A JSF Renderer is responsible for two functions, rendering component as HTML markup and processing request attributes. While processing attributes in the code is usually simple, generating markup in the Java code may be cumbersome for big components. It is conceptually difficult to visualize the two-step process by which calls to a ResponseWriter are converted into HTML, and then the HTML and CSS are subsequently transformed into a visual representation.  Also, each element and attribute require five times more characters than the generated string itself, this makes the renderer code much bigger than the original design.  JSF 2.0 offers “composite components” for code reuse to alleviate some of these concerns, but developers og native component are still stuck writing dozens of startElement/writeAttribute/writeText/endElement calls.


RichFaces CDK closes the gap between component HTML design and Java code. It lets the developer create a XHTML template, similar to a composite component, and converts that template to Java code. This template reuses JSF 2 composite component syntax where possible - this lets developers prototype a component as a composite-component, and later convert it to a native component for production with better performance and extended functionality.

Renderer Template

Base structure

The Renderer template is well-formed XML file, similar to a JSF composite component, . The main difference is that a CDK template should havea  document element <root> from the cdk namespace "http://jboss.org/schema/richfaces/cdk/core". To allow XML validation for non-standard HTML attributes, the default namespace should be "http://jboss.org/schema/richfaces/cdk/xhtml-el", associated with CDK xml schema. The full list of template schemes is described in the table below:

 

Namespace URISchema locationDescription
"http://jboss.org/schema/richfaces/cdk/xhtml-el"http://jboss.org/schema/richfaces/cdk/xhtml-el.xsdHTML 4.0.1 with CDK extensions.
"http://jboss.org/schema/richfaces/cdk/core"http://jboss.org/schema/richfaces/cdk/cdk-template.xsdCDK template document
"http://jboss.org/schema/richfaces/cdk/jstl/core"http://jboss.org/schema/richfaces/cdk/cdk-jstl-core.xsdCDK version of JSTL tags
"http://jboss.org/schema/richfaces/cdk/jsf/composite"http://jboss.org/schema/richfaces/cdk/cdk-composite.xsdCDK version of JSF 2 composite component tags
"http://jboss.org/schema/richfaces/cdk/ext"http://jboss.org/schema/richfaces/cdk/cdk-extensions.xsdExtensions for HTML attributes to process component pass-throuth attributes

 

As with the JSF composite component, the CDK contains two main sections: an interface with the meta information necessary to generate a Renderer and an implementation consisting of HTML markup.

<composite:interface> Element

The interface section supports <composite:attribute> elements from the JSF composite component, with children <composite:clientBehavior> elements. The syntax is the same as for composite component, but the meaning is different: These elements define renderer-specific component attributes. In a renderer-specific component generated by the CDK, these attributes will be added to the component, and the generated code will use getter and setter methods for them instead of an attribute Map.

In addition, there are CDK-specific elements used only by the CDK:

  • <cdk:class>, a fully-qualified Java class name for the generated renderer. By default, CDK infers the name for the generated class using naming conventions.
  • <cdk:superclass>, a fully-qualified Java class name for the superclass of the generated Renderer. This superclass should extend javax.faces.render.Renderer, and can be used to hold decode logic and helper methods. A renderer's default superclass is the javax.faces.render.Renderer class.
  • <cdk:component-family>, the JSF component family ID, used to associate the renderer with a component. By default, this value is calculated using naming conventions or taken from the UIComponent class annotation that contains a renderer attribute referrenced to this template.
  • <cdk:renderer-type>, the JSF Renderer type assigned to the generated renderer. Same as for the component family, its value can be inferred or taken from the UIComponent.
  • <cdk:renderkit-id>, the JSF render kit for which the generated renderer belongs to. By default, this value is JSF HTML_BASIC render kit.
  • <cdk:renders-children>, the logical value ( true or false ) that should be returned from the getRendersChildren method. By default, CDK doesn’t override that method from the superclass.
  • <cdk:import> defines additional Java import directives for the generated class. Attributes:
    • package - fully qualified Java package name
    • names - short names for imported classes, comma-separated list
    • static - tells CDK to generate “import static” directive
  • <cdk:import-attributes> allows CDK to import attributes definition from a faces-config fragment, the same fragment used by the @JsfComponent#attributes . The ‘src’ attributes should contain the URL for that fragment.
  • <cdk:resource-dependency> defines the JSF resource used by the component. The resource defined by that element is added to the @ResourceDependencies annotation for the generated type. Attributes:
    • name - defines resource name.
    • library - optional, defines resource library name
    • target - optional, forces resource to be rendered in HTML head, body, or form element.

 

<composite:implementation>

While the <interface> section defines meta-information, most of the Renderer code is generated from the content of the <implementation> element. This HTML content is converted to ResponseWriter startElement / writeAttribute / endElement method calls.

Encoding child components

A JSF Renderer has three methods that participate in the encoding process: encodeBegin, encodeChildren and encodeEnd. For components that do not contain child elements ( input field, for example ), it’s better to perform encoding in the single method, usually encodeEnd. If the component's children are encoded in natural order, the developer can use the default encodeChildren functionality, and render the component prolog in the encodeBegin() and finish it in the encodeEnd.  For components that change the rendering sequence of its children, rendering of the content is usually performed in the encodeChildren method, with the rendersChildren method returning true ( see <cdk:renders-children> element above ).

 

To define methods used for encoding, the developer can put a <cdk:body> element. Everything before that element maps to the encodeBegin method, and rest of the <composite:implementation> content after <cdk:body> maps to the encodeEnd method. If this element is empty, no encodeChildren method is generated unless the ‘enforce’ attribute is set to true, so encoding of the child components is performed by default in thesuperclass. Otherwise, the content of the <cdk:body> is generated inside the encodeChildren method.

EL-expressions

CDK evaluates Expression Language statements into Java code. It supports Expression Language 2.2 syntax, and recognises their argument types where possible. Because expressions are generated as Java code, type checking is more strict than what is allowed in the dynamic interpreter. For example it impossible to access an unknown method or field if the argument is recognized as an Object.


EL-expressions are allowed in text, HTML attributes, and flow control directives. CDK does not yet recognise EL-expressions as HTML element names.

 

To call a method that returns void, use the <cdk:call> element, with the call expression provided in the element body or by the ‘expression’ attribute.

Flow control

CDK supports JSTL-like directives to control rendering:

  • <c:if> is used to generate Java if() statements. The content of the ‘test’ attribute is used to generate the condition expression, usually from an EL-expression.
  • <c:choose> with <c:when> and <c:otherwise> children elements is used to chain Java if() ...else if() … else statements. The ‘test’ attribute of each <c:when> element is used to generate conditions, and content of the <c:otherwise> maps to the final else {} block.
  • <c:forEach> is used for iterations over collections. Its ‘items’ attribute should be evaluated to a Java Collection or array ( Iterator/Enumeration not yet supported), and the variable defined by the ‘var’ attribute can be used in EL-expressions inside the iteration.
  • <cdk:switch> with <cdk:case> and <cdk:default> elements are used to construct Java ‘switch’ directives. The ‘key’ attribute is used to define a "switch()" condition, and the ‘values’ attribute from <cdk:case> is used to generate a "case … :" statement.  Of course, these expressions should be evaluated to types which are valid for Java switch/case statement.

Variables

CDK can assign computation results to variables, which can be used in EL-expressions. Predefined variable names are:

  • component - the UIComponent used to call Renderer#encode...() method.
  • facesContext - the current FacesContext instance.
  • clientId - client id of component used to call Rendered method.
  • responseWriter - instance of JSF ResponceWriter used to write Renderer output.

 

Developer's can define their own variables using the <cdk:object> element. The variable name is defined by the ‘name’ attribute, and the value is evaluated from the ‘value’ attribute or the element body.

 

The scope of object is the current Java block.  As such objects defined in one of the different parts (sepatated by the <cdk:body> statement) are not visible in the other parts because they are going in different methods. Also, variables defined inside a flow control elements are not visible outside of the element.

Attributes

In a typical component, most HTML attributes aregenerated from the component's attributes. There are two cases for each attribute:

  1. Attribute value generated as the String.
  2. Pass through attribute, whose content comes from the component attribute, with optional behavior-generated event handlers.

 

For the first case, the developer can provide an attribute value as a literal or EL-expression.  The CDK recognises HTML 4 schema (HTML5 schema not yet implemented) and properly render URL and boolean values.

 

In the second case, the developer can use attributes from the CDK extensions namespace. Each HTML attribute has its ‘extension’ version. For these attributes, The CDK treats the attribute value as the name of the component attribute from which the attribute value comes. If the component attribute was not set, no HTML attribute will be rendered. For attributes with associated ClientBehavior events the component renders scripts from all behaviors for that event.


To reduce the amount of code in the component template, there are three attributes for bulk operations:

  • cdk:passThroughWithExclusions, this renders all attributes allowed for an HTML element except ones defined in the attribute value (space separated list). The CDK expects that the component attribute name the same as for HTML. This is useful to render single-element components or for the root element.
  • cdk:passThrough renders all attributes defined in its value (space-separated list). If the component and HTML attributes have the same name, it is typed as is. Otherwise, the developer can provide a component attribute name separated by colon.  For example: <cdk:passThrough=” style class:styleClass”, means render the component ‘style’ attribute as HTML style, and component#styleClass as HTML class.