java jsf java-ee custom-component renderer

java - ¿Cuál es la relación entre la familia de componentes, el tipo de componente y el tipo de renderizador?



jsf java-ee (2)

El javadoc dice de getFamily() :

Devuelve el identificador de la familia de componentes a la que pertenece este componente. Este identificador, junto con el valor de la propiedad rendererType , se puede usar para RenderKit#getRenderer() el Renderer apropiado para esta instancia de componente.

La justificación de los mantenedores está cubierta en la especificación JSF :

Familia de componentes

Cada clase de componente de interfaz de usuario estándar tiene un valor estándar para la familia de componentes, que se utiliza para buscar representadores asociados con este componente. Las subclases de una clase UIComponent genérica generalmente heredarán esta propiedad de su superclase, de modo que los renderizadores que solo esperan la superclase aún podrán procesar subclases especializadas.

Interpreto que esto proporciona cierta capacidad para la verificación de tipos adicional más allá del tipo de clase de Java (ya que las subclases siempre serán subclases). No estoy seguro de cuán útil sea esto.

Cuando estoy aprendiendo el desarrollo de componentes personalizados en JSF, me confundí con la relación entre la familia de componentes, el tipo de componente y el tipo de procesador. Por ejemplo, registré un renderizador y un componente personalizado como se muestra a continuación.

faces-config.xml :

<component> <component-type>study.faces.Div</component-type> <component-class>javax.faces.component.UIPanel</component-class> </component> <render-kit> <render-kit-id>HTML_BASIC</render-kit-id> <renderer> <component-family>javax.faces.Panel</component-family> <renderer-type>study.faces.DivRenderer</renderer-type> <renderer-class>com.study.ui.DivRenderer</renderer-class> </renderer> </render-kit>

También my.taglib.xml una nueva etiqueta en el archivo my.taglib.xml como se muestra a continuación:

<tag> <tag-name>div</tag-name> <component> <component-type>study.faces.Div</component-type> <renderer-type>study.faces.DivRenderer</renderer-type> </component> </tag>

Esta configuración funciona muy bien. Sin embargo, no entendí por qué se requiere la línea <component-family>javax.faces.Panel</component-family> en el registro del renderizador. En my.taglib.xml , el componente y el renderizador están conectados y, IMHO, debería haber sido suficiente para seleccionar un renderizador apropiado para el componente. ¿Cuál es el uso del parámetro adicional <component-family> ?

Hice búsquedas en Google y todas las respuestas que recibí dicen como "Se puede usar un renderizador para renderizar múltiples componentes. Estos componentes pertenecen a una familia". Pero estas declaraciones no aclararon mi confusión. ¿Puede alguien explicar la relación entre el tipo de componente, la familia de componentes y la estrategia de selección del renderizador? (Esperemos con un buen ejemplo.)


El renderizador es seleccionado por la familia de componentes, no por el tipo de componente como parece esperar.

Vamos a citar la especificación JSF 2.0 :

3.1.2 Tipo de componente

Si bien no es una propiedad de UIComponent, el tipo de componente es un dato importante relacionado con cada subclase UIComponent que permite que la instancia de la Application cree nuevas instancias de subclases UIComponent con ese tipo. Consulte la Sección 7.1.11 "Fábricas de objetos" para obtener más información sobre el tipo de componente.

3.1.3 Familia de componentes

Cada clase de componente de interfaz de usuario estándar tiene un valor estándar para la familia de componentes, que se utiliza para buscar representadores asociados con este componente. Las subclases de una clase UIComponent genérica generalmente heredarán esta propiedad de su superclase, de modo que los renderizadores que solo esperan la superclase aún podrán procesar subclases especializadas.

Básicamente, el tipo de componente es obligatorio para JSF para crear el componente mediante Application#createComponent() método Application#createComponent() .

UIComponent component = context.getApplication().createComponent("study.faces.Div");

Esto tiene la ventaja de que el componente study.faces.Div no es una dependencia de tiempo de compilación y, por lo tanto, ofrece polimorfismo en tiempo de ejecución y posibilidades de conectividad (si está familiarizado con el mecanismo Class#forName() JDBC y sus fábricas , entonces comprenderá que mejor parte).

Cada tipo de componente pertenece a una familia que puede constar de uno o más componentes. El renderizador se selecciona según la familia de componentes y el tipo de renderizador por RenderKit#getRenderer()

Renderer renderer = context.getRenderKit().getRenderer(component.getFamily(), component.getRendererType());

El renderizador no se selecciona según el tipo de componente y el tipo de renderizador. Esto permite la reutilización del renderizador para múltiples tipos de componentes que pertenecen a una familia de componentes. De lo contrario, tendría que registrar un solo renderizador para cada componente individual a pesar de que los componentes podrían compartir el mismo renderer.

La siguiente entrada faces-config.xml

<component> <component-type>study.faces.Div</component-type> <component-class>javax.faces.component.UIPanel</component-class> </component>

le dice a JSF que la Application debe crear una instancia de la clase de componente dada cada vez que se crea un componente del tipo de componente dado. La familia de componentes no está especificada allí, porque eso ya se conoce implícitamente por component.getFamily() .

Y la siguiente entrada faces-config.xml

<render-kit> <renderer> <component-family>javax.faces.Panel</component-family> <renderer-type>study.faces.DivRenderer</renderer-type> <renderer-class>com.study.ui.DivRenderer</renderer-class> </renderer> </render-kit>

le dice a JSF que el RenderKit debe devolver una instancia de la clase de renderizador dada cada vez que se solicita un renderizador de la familia de componentes y el tipo de renderizador dados.

La siguiente entrada .taglib.xml

<tag> <tag-name>div</tag-name> <component> <component-type>study.faces.Div</component-type> <renderer-type>study.faces.DivRenderer</renderer-type> </component> </tag>

le dice a JSF (bueno, Facelets) que la etiqueta dada debe crear un componente del tipo de componente dado en la raíz de la vista (cuya clase ha sido definida en faces-config.xml ) y que su tipo de procesador debe configurarse al tipo de procesador dado . Tenga en cuenta que el tipo de componente no se utiliza para seleccionar el procesador, en su lugar, se utiliza para crear un componente en la raíz de la vista. También tenga en cuenta que la entrada de tipo de renderizador es opcional. De lo contrario, se utilizará el propio tipo de procesador predefinido del componente. Esto permite reutilizar los tipos de componentes existentes con un tipo de renderizador diferente.