jsr372-experts@javaserverfaces-spec-public.java.net

[jsr372-experts] 1271-OverrideComponentRenderer

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Fri, 17 Oct 2014 18:36:01 +0200

Hi,

I submitted https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1271
a while ago, with the intend of making the specific task of overriding
a renderer for a given component easier.

Manfred then 'discovered' a trick that somewhat diminishes the need
for this, which he described here:
https://weblogs.java.net/blog/mriem/archive/2014/10/16/jsf-tip-63-another-way-override-renderer

However, even though this makes a local override really easy and could
be globally re-used by packaging the required tags into a Facelet tag,
studying it did reveal one kinda problematic hurdle; the need to
retrieve from somewhere the *component family*.

As it appears this is not entirely trivial for a regular user to discover.

From the h:panelGroup tag, one may get to the -taglib.xml that lists
the following for the panelGroup tag:

<tag-name>panelGroup</tag-name>
<component>
    <component-type>javax.faces.HtmlPanelGroup</component-type>
    <renderer-type>javax.faces.Group</renderer-type>
</component>

From here we figured many users would be stuck. And in fact, even
getting here might not be entirely trivial (Mojarra hides this file in
a non-obvious package, and only puts the .tld file in the more obvious
META-INF one).

In this case, we know component type javax.faces.HtmlPanelGroup maps
to class javax.faces.component.html.HtmlPanelGroup and the family
should be obtainable via the getFamily() method (which happens to live
in the javax.faces.component.UIPanel base). Here we finally learn that
this family name we're after is "javax.faces.Panel".

Clearly this is quite a hurdle for users and even though the actual
override looks easy in theory, it's thus still difficult in practice.

A few ideas to somewhat simplify this process:

1. *-types default to class names (where possible, and if applicable)
2. Extend taglib-xml to contain the family etc data users need
3. Make the same data discoverable via annotations
4. Reference things by the fully qualified tag name
5. Provide APIs to query data like component, renderer, family name,
etc based on fully qualified tag name

Ad 1

Instead of having component javax.faces.HtmlPanelGroup we could just
have javax.faces.component.html.HtmlPanelGroup as the type string.
This could still be mapped to a totally different class, but by
default (or in absence of any explicit mapping) it would default to a
class with that FQN.

Some types like renderer type javax.faces.Group as used in the example
above maps to an implementation specific class, e.g. to
com.sun.faces.renderkit.html_basic.GroupRenderer in case of Mojarra.
So this would not be a hard rule, just a default.

Ad 2/3

This ties in with some existing issues to enhance the taglib-xml
format and to provide that same data on the artefact itself via
annotations. E.g. JAVASERVERFACES_SPEC_PUBLIC-1193,
JAVASERVERFACES_SPEC_PUBLIC-1190

Ad 4

A fully qualified tag name already embodies to the runtime all
information that's needed, since naturally the runtime uses this to
lookup the actual component, renderer etc. Users quite often think in
terms of this tag name, since it's their main entry point into
component usage. There's already at least one place in the API that
accepts a taglib URI + tag name, namely
ViewDeclarationLanguage#createComponent

For convenience we could extend this to other parts of the API; as
extra attributes on tags where applicable or as (overloaded) methods
in the API.

Ad 5

For components a lot can probably be done via
ViewDeclarationLanguage#createComponent already, but having access to
some of the required data is more of a side-effect of that call than
its actual main purpose. For this I was thinking more along the lines
of returning some meta data structure instead of actually creating
component instances.

What do you think?

Kind regards,
Arjan Tijms