返回介绍

13.18.2 用 Introspector 提取 BeanInfo

发布于 2024-10-15 23:56:29 字数 6871 浏览 0 评论 0 收藏 0

当我们拖放一个 Bean 的调色板并将它放入到窗体中时,一个 Bean 的最关键的部分的规则发生了。应用程序构建工具必须可以创建 Bean(如果它是默认的构建器的话,它就可以做)然后,在此范围外访问 Bean 的源代码,提取所有的必要的信息以创立属性表和事件处理器。

解决方案的一部分在 11 章结尾部分已经显现出来:Java 1.1 版的映象允许一个匿名类的所有方法被发现。这完美地解决了 Bean 的难题而无需我们使用一些特殊的语言关键字像在其它的可视化编程语言中所需要的那样。事实上,一个主要的原因是映象增加到 Java 1.1 版中以支持 Beans(尽管映象同样支持对象串联和远程方法调用)。因为我们可能希望应用程序构建工具的开发者将不得不映象每个 Bean 并且通过它们的方法搜索以找到 Bean 的属性和事件。

这当然是可能的,但是 Java 的研制者们希望为每个使用它的用户提供一个标准的接口,而不仅仅是使 Bean 更为简单易用,不过他们也同样提供了一个创建更复杂的 Bean 的标准方法。这个接口就是 Introspector 类,在这个类中最重要的方法静态的 getBeanInfo()。我们通过一个类处理这个方法并且 getBeanInfo() 方法全面地对类进行查询,返回一个我们可以进行详细研究以发现其属性、方法和事件的 BeanInfo 对象。

通常我们不会留意这样的一些事物——我们可能会使用我们大多数的现成的 Bean,并且我们不需要了解所有的在底层运行的技术细节。我们会简单地拖放我们的 Bean 到我们窗体中,然后配置它们的属性并且为事件编写处理器。无论如何它都是一个有趣的并且是有教育意义的使用 Introspector 来显示关于 Bean 信息的练习,好啦,闲话少说,这里有一个工具请运行它(我们可以在 forgbean 子目录中找到它):

//: BeanDumper.java
// A method to introspect a Bean
import java.beans.*;
import java.lang.reflect.*;

public class BeanDumper {
  public static void dump(Class bean){
    BeanInfo bi = null;
    try {
      bi = Introspector.getBeanInfo(
        bean, java.lang.Object.class);
    } catch(IntrospectionException ex) {
      System.out.println("Couldn't introspect " +
        bean.getName());
      System.exit(1);
    }
    PropertyDescriptor[] properties = 
      bi.getPropertyDescriptors();
    for(int i = 0; i < properties.length; i++) {
      Class p = properties[i].getPropertyType();
      System.out.println(
        "Property type:\n  " + p.getName());
      System.out.println(
        "Property name:\n  " + 
        properties[i].getName());
      Method readMethod = 
        properties[i].getReadMethod();
      if(readMethod != null)
        System.out.println(
          "Read method:\n  " + 
          readMethod.toString());
      Method writeMethod = 
        properties[i].getWriteMethod();
      if(writeMethod != null)
        System.out.println(
          "Write method:\n  " +
          writeMethod.toString());
      System.out.println("====================");
    }
    System.out.println("Public methods:");
    MethodDescriptor[] methods =
      bi.getMethodDescriptors();
    for(int i = 0; i < methods.length; i++)
      System.out.println(
        methods[i].getMethod().toString());
    System.out.println("======================");
    System.out.println("Event support:");
    EventSetDescriptor[] events = 
      bi.getEventSetDescriptors();
    for(int i = 0; i < events.length; i++) {
      System.out.println("Listener type:\n  " +
        events[i].getListenerType().getName());
      Method[] lm = 
        events[i].getListenerMethods();
      for(int j = 0; j < lm.length; j++)
        System.out.println(
          "Listener method:\n  " +
          lm[j].getName());
      MethodDescriptor[] lmd = 
        events[i].getListenerMethodDescriptors();
      for(int j = 0; j < lmd.length; j++)
        System.out.println(
          "Method descriptor:\n  " +
          lmd[j].getMethod().toString());
      Method addListener = 
        events[i].getAddListenerMethod();
      System.out.println(
          "Add Listener Method:\n  " +
        addListener.toString());
      Method removeListener =
        events[i].getRemoveListenerMethod();
      System.out.println(
        "Remove Listener Method:\n  " +
        removeListener.toString());
      System.out.println("====================");
    }
  }
  // Dump the class of your choice:
  public static void main(String[] args) {
    if(args.length < 1) {
      System.err.println("usage: \n" +
        "BeanDumper fully.qualified.class");
      System.exit(0);
    }
    Class c = null;
    try {
      c = Class.forName(args[0]);
    } catch(ClassNotFoundException ex) {
      System.err.println(
        "Couldn't find " + args[0]);
      System.exit(0);
    }
    dump(c);
  }
} ///:~

BeanDumper.dump() 是一个可以做任何工作的方法。首先它试图创建一个 BeanInfo 对象,如果成功地调用 BeanInfo 的方法,就产生关于属性、方法和事件的信息。在 Introspector.getBeanInfo() 中,我们会注意到有一个另外的自变量。由它来通知 Introspector 访问继承体系的地点。在这种情况下,它在分析所有对象方法前停下,因为我们对看到那些并不感兴趣。

因为属性,getPropertyDescriptors() 返回一组的属性描述符号。对于每个描述符号我们可以调用 getPropertyType() 方法彻底的通过属性方法发现类的对象。这时,我们可以用 getName() 方法得到每个属性的假名(从方法名中提取),getname() 方法用 getReadMethod() 和 getWriteMethod() 完成读和写的操作。最后的两个方法返回一个可以真正地用来调用在对象上调用相应的方法方法对象(这是映象的一部分)。对于公共方法(包括属性方法),getMethodDescriptors( )返回一组方法描述字符。每一个我们都可以得到相当的方法对象并可以显示出它们的名字。

对于事件而言,getEventSetDescriptors() 返回一组事件描述字符。它们中的每一个都可以被查询以找出接收器的类,接收器类的方法以及增加和删除接收器的方法。BeanDumper 程序打印出所有的这些信息。

如果我们调用 BeanDumper 在 Frog 类中,就像这样:

java BeanDumper frogbean.Frog

它的输出结果如下(已删除这儿不需要的额外细节):

class name: Frog
Property type:
  Color
Property name:
  color
Read method:
  public Color getColor()
Write method:
  public void setColor(Color)
====================
Property type:
  Spots
Property name:
  spots
Read method:
  public Spots getSpots()
Write method:
  public void setSpots(Spots)
====================
Property type:
  boolean
Property name:
  jumper
Read method:
  public boolean isJumper()
Write method:
  public void setJumper(boolean)
====================
Property type:
  int
Property name:
  jumps
Read method:
  public int getJumps()
Write method:
  public void setJumps(int)
====================
Public methods:
public void setJumps(int)
public void croak()
public void removeActionListener(ActionListener)
public void addActionListener(ActionListener)
public int getJumps()
public void setColor(Color)
public void setSpots(Spots)
public void setJumper(boolean)
public boolean isJumper()
public void addKeyListener(KeyListener)
public Color getColor()
public void removeKeyListener(KeyListener)
public Spots getSpots()
======================
Event support:
Listener type:
  KeyListener
Listener method:
  keyTyped
Listener method:
  keyPressed
Listener method:
  keyReleased
Method descriptor:
  public void keyTyped(KeyEvent)
Method descriptor:
  public void keyPressed(KeyEvent)
Method descriptor:
  public void keyReleased(KeyEvent)
Add Listener Method:
  public void addKeyListener(KeyListener)
Remove Listener Method:
  public void removeKeyListener(KeyListener)
====================
Listener type:
  ActionListener
Listener method:
  actionPerformed
Method descriptor:
  public void actionPerformed(ActionEvent)
Add Listener Method:
  public void addActionListener(ActionListener)
Remove Listener Method:
  public void removeActionListener(ActionListener)
====================

这个结果揭示出了 Introspector 在从我们的 Bean 产生一个 BeanInfo 对象时看到的大部分内容。我们可注意到属性的类型和它们的名字是相互独立的。请注意小写的属性名。(当属性名开头在一行中有超过不止的大写字母,这一次程序就不会被执行。)并且请记住我们在这里所见到的方法名(例如读和与方法)真正地从一个可以被用来在对象中调用相关方法的方法对象中产生。

通用方法列表包含了不相关的事件或者属性,例如 croak()。列表中所有的方法都是我们可以有计划的为 Bean 调用,并且应用程序构建工具可以选择列出所有的方法,当我们调用方法时,减轻我们的任务。

最后,我们可以看到事件在接收器中完全地分析研究它的方法、增加和减少接收器的方法。基本上,一旦我们拥有 BeanInfo,我们就可以找出对 Bean 来说任何重要的事物。我们同样可以为 Bean 调用方法,即使我们除了对象外没有任何其它的信息(此外,这也是映象的特点)。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文