El Interface BeanInfo

¿Cólo examinan las herramientas de desarrollo a un Bean para exponer sus caracterísitcas (propiedades, eventos y métodos) en un hoja de propiedades? Utilizando la clase java.beans.Introspector. Esta clase utiliza el corazón de reflexión del API del JDK para descubrir los métodos del Bean, y luego aplica los patrones de diseño de los JavaBeans para descubrir sus caracterísitcas. Este proceso de descubrimiento se llama introspección.

De forma alternativa, se pueden exponer explícitamente las caractericas del Bean en una clase asociada separada que implemente el interface BeanInfo. Asociando una clase BeanInfo con un Bean se puede:

BeanInfo define métodos que devuelven descriptores para cada propiedad, método o evento que se quiere exponer. Aquí tienes los prototipos de estos métodos:

PropertyDescriptor[] getPropertyDescriptors();
MethodDescriptor[]   getMethodDescriptors();
EventSetDescriptor[] getEventSetDescriptors();
Cada uno de estos métodos devuelve un array de descriptores para cada caracterísitca.

Descriptores de Caracterisitcas

Las clases BeanInfo contienen descriptores que precisamente describen las características del Bean fuente. El BDK implementa las siguientes clases:

El interface BeanInfo declara métodos que devuelven arrays de los descriptores anteriores.

Crear una Clase BeanInfo

Utilizaremos la clase ExplicitButtonBeanInfo para ilustrar la creación de una clase BeanInfo. Aquí están los pasos generales para crear una clase BeanInfo:
  1. Nombrar la clase BeanInfo. Se debe añadir el estring "BeanInfo" al nombre de la clase fuente. Si el nombre de la clase fuente es ExplicitButton, la clase BeanInfo asociada se debe llamar ExplicitButtonBeanInfo

  2. Subclasificar SimpleBeanInfo. Esta es una clase de conveniencia que implementa los métodos de BeanInfo para que devuelvan null o un valor nulo equivalente.
         public class ExplicitButtonBeanInfo extends SimpleBeanInfo {
         
    Utilizando SimpleBeanInfo nos ahorramos tener que implementar todos los métodos de BeanInfo; solo tenemos que sobreescribir aquellos métodos que necesitemos.

  3. Sobreescribir los métodos apropiados para devolver las propiedades, los métodos o los eventos que queremos exponer. ExplicitButtonBeanInfo sobreescribe el método getPropertyDescriptors() para devolver cuatro propiedades:
         public PropertyDescriptor[] getPropertyDescriptors() {
          try {  
           PropertyDescriptor background =
             new PropertyDescriptor("background", beanClass);
           PropertyDescriptor foreground =
             new PropertyDescriptor("foreground", beanClass);
           PropertyDescriptor font =
             new PropertyDescriptor("font", beanClass);
           PropertyDescriptor label =
             new PropertyDescriptor("label", beanClass);
     
           background.setBound(true);
           foreground.setBound(true);
           font.setBound(true);
           label.setBound(true);
             
           PropertyDescriptor rv[] =
             {background, foreground, font, label};
           return rv;
          } catch (IntrospectionException e) {
             throw new Error(e.toString());
            }
         }        
         
    Existen dos cosas importantes que observar aquí:
    • Si se deja fuera algún descriptor, la propiedad, evento o método no descrito no se expondrá. En otras palabras, se puede exponer selectivamente las propiedades, eventos o métodos, dejando fuera las que no queramos exponer.
    • Si un método obtenedor de características (por ejemplo getMethodDescriptor()) devuelve Null, se utilizará la reflexión de bajo nivel para esa caracterísitca. Esto significa, por ejemplo, que se pueden expecificar explicitamente propiedades, y dejar que la reflexión de bajo nivel descubra los métodos. Si no se sobreescribe el método por defecto de SimpleBeanInfo que devuelve null, la reflexión de bajo nivel se utilizará para esta característica.

  4. Optionalmente, asociar un icono con el Bean fuente.
          public java.awt.Image getIcon(int iconKind) {
            if (iconKind == BeanInfo.ICON_MONO_16x16 ||
                iconKind == BeanInfo.ICON_COLOR_16x16 ) {
                java.awt.Image img = loadImage("ExplicitButtonIcon16.gif");
                return img;
            }
            if (iconKind == BeanInfo.ICON_MONO_32x32 ||
                iconKind == BeanInfo.ICON_COLOR_32x32 ) {
                java.awt.Image img = loadImage("ExplicitButtonIcon32.gif");
                return img;
            }
            return null;
          }
         
    El BeanBox muestra el icono junto al nombre del Bean en el ToolBox. Se puede esperar que las herramientas de desarrollo hagan algo similar.

  5. Especificar la clase del Bean fuente, y , si el Bean está personalizado, especificarlo también.
         public BeanDescriptor getBeanDescriptor() {
            return new BeanDescriptor(beanClass, customizerClass);
         }
         ...
         private final static Class beanClass = ExplicitButton.class;
         private final static Class customizerClass = OurButtonCustomizer.class;
         

Guarda la clase BeanInfo en el mismo directorio que la clase fuente. El BeanBox busca primero la clase BeanInfo de un Bean en el path del paquete del Bean. Si no se encuentra el BeanInfo, entonces la información del Bean busca en el path (mantenido por el Introspector). La información del Bean se busca por defecto en el path sun.beans.infos. Si no se encuentra la clase BeanInfo, se utiliza la reflexión de bajo nivel para descrubrir las características del Bean.

Utilizar BeanInfo para Controlar las Características a Exponer

Si relegamos en la reflexión del bajo nivel para descubrir las características del Bean, todas aquellas propiedades, métodos y eventos que conformen el patrón de diseño apropiado serán expuestas en una herramienta de desarrollo. Esto incluye cualquier característica de la clase base. Si el BeanBox encuentra una clase BeanInfo asociada, entonces la información es utiliza en su lugar, y no se examinan más clases base utilizando la reflexión. En otras palabras, la información del BeanInfo sobreescribe la información de la reflexión de bajo nivel, y evita el examen de la clase base.

Mediante la utilización de una clase BeanInfo, se pueden exponer subconjuntos de una característica particular del Bean. Por ejemplo, mediante la no devolución de un método descriptor para un método particular, ese método no será expuesto en una herramienta de desarrollo.

Cuando se utiliza la clase BeanInfo

Localizar las clases BeanInfo

Antes de examinar un Bean, el Introspector intentará encontrar una clase BeanInfo asociada con el bean. Por defecto, el Introspector toma el nombre del paquete del Bean totalmente cualificado, y le añade "BeanInfo" para formar un nuevo nombre de clase. Por ejemplo, si el Bean fuente es sunw.demo.buttons.ExplicitButton, el Introspector intentará localizar sunw.demo.buttons.ExplicitButtonBeanInfo.

Si esto falla, se buscará en todos los paquetes en el path de BeanInfo. El path de búsqueda de BeanInfo es mantenido por Introspector.setBeanInfoSearchPath() y Introspector.getBeanInfoSearchPath().


Ozito