Welcome

首页 / 软件开发 / JAVA / 用Introspector提取BeanInfo

用Introspector提取BeanInfo2007-05-29 yycnet.yeah.net yyc译当我们拖放一个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 Beanimport 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:
" + p.getName());System.out.println("Property name:
" + properties[i].getName());Method readMethod = properties[i].getReadMethod();if(readMethod != null)System.out.println("Read method:
" + readMethod.toString());Method writeMethod = properties[i].getWriteMethod();if(writeMethod != null)System.out.println("Write method:
" +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:
" +events[i].getListenerType().getName());Method[] lm = events[i].getListenerMethods();for(int j = 0; j < lm.length; j++)System.out.println("Listener method:
" +lm[j].getName());MethodDescriptor[] lmd = events[i].getListenerMethodDescriptors();for(int j = 0; j < lmd.length; j++)System.out.println("Method descriptor:
" +lmd[j].getMethod().toString());Method addListener = events[i].getAddListenerMethod();System.out.println("Add Listener Method:
" +addListener.toString());Method removeListener =events[i].getRemoveListenerMethod();System.out.println("Remove Listener Method:
" +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: 
" +"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: FrogProperty type:ColorProperty name:colorRead method:public Color getColor()Write method:public void setColor(Color)====================Property type:SpotsProperty name:spotsRead method:public Spots getSpots()Write method:public void setSpots(Spots)====================Property type:booleanProperty name:jumperRead method:public boolean isJumper()Write method:public void setJumper(boolean)====================Property type:intProperty name:jumpsRead 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:KeyListenerListener method:keyTypedListener method:keyPressedListener method:keyReleasedMethod 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:ActionListenerListener method:actionPerformedMethod 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调用方法,即使我们除了对象外没有任何其它的信息(此外,这也是映象的特点)。