Извлечение BeanInfo с помощью Инспектора
Одна из наиболее критичных частей компонентной схемы возникает, когда вы перетаскиваете компонент (Bean) из палитры и бросаете его в форму. Построитель приложения должен быть способен создать компонент (Bean) (что выполняется с помощью конструктора по умолчанию), а затем, без доступа к исходному коду компонента (Bean), получить всю необходимую информацию для создания страничек свойств и обработчиков событий.
Часть решения ясно видна в конце Главы 12: рефлексия Java позволяет обнаружить все методы анонимных классов. Это совершенное решение проблемы компонента (Bean) без введения любых дополнительных ключевых слов, которые требуются в других визуальных языках программирования. Фактически, одна из главнейших причин добавления рефлексии в Java была в поддержке компонентов (Bean) (хотя рефлексия также поддерживает сериализацию объектов и удаление обращений к методам). Так что вы можете ожидать, что создатель построителя приложения будет рефлектировать каждый компонент (Bean) и охотится за его методами для нахождения свойств и событий для этого компонента (Bean).
Это, конечно, возможно, но разработчики Java хотели обеспечить стандартный инструмент, не только для упрощения использования компонент (Bean), но и для обеспечения стандартного подхода для создания более сложных компонент (Bean). Этим инструментом является класс Introspector, и наиболее важным методом этого класса является static getBeanInfo( ). Вы передаете ссылку на Class в этот метод, и он полностью опрашивает этот класс и возвращает объект BeanInfo, который вы можете затем раскрыть для нахождения свойств, методов и србытий.
Обычно вы не заботитесь об этом — вероятно, вы получите большинство ваших компонентов (Bean) от продавца, и вам не нужно будет знать всю магию, которая происходит внутри. Вы просто перетаскиваете ваш компонент (Bean) на вашу форму, затем конфигурируете его свойства и пишите обработчик для интересующих вас событий. Однако очень интересно и познавательно использовать Introspector для отображения информации о компоненте (bean), так что вот инструмент, который делает это:
//: c13:BeanDumper.java
dmpr.actionPerformed( new ActionEvent(dmpr, 0, "")); } public static void main(String[] args) { Console.run(new BeanDumper(), 600, 500); } } ///:~
BeanDumper.dump( ) - это метод, который делает всю работу. Сначала он пробует создать объект BeanInfo, и если это происходит успешно, вызывает метод BeanInfo, который производит информацию о свойствах, методах и событиях. В Introspector.getBeanInfo( ), вы увидите второй аргумент. Это говорит Introspector, где остановится в иерархии наследования. Здесь он остановится прежде, чем разберет все методы от Object, так как мы не интересуемся ими.
Для свойств: getPropertyDescriptors( ) возвращает массив из PropertyDescriptor. Для каждого PropertyDescriptor вы можете вызвать getPropertyType( ) для нахождения класса объекта, который передается и получается через методы свойства. Затем, для каждого свойства вы можете получить псевдоним (получается из имени метода) с помощью getName( ), метод для чтения с помощью getReadMethod( ), и метод для записи с помощью getWriteMethod( ). Последние два метода возвращают объект Method, который может на самом деле использоваться для вызова соответствующего метода объекта (это часть рефлексии).
Для public методов (включая методы свойств) getMethodDescriptors( ) возвращает массив MethodDescriptor. Для каждого их них вы можете получить ассоциированный объект Method и напечатать его имя.
Для событий getEventSetDescriptors( ) возвращает массив (как вы думаете, чего?) EventSetDescriptor. Каждый элемент массива может быть опрошен для нахождения класса слушателя, методов класса слушателя и методов добавления (add-) и удаления (remove-). Программа 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 в качестве объекта BeanInfo для вашего компонента (Bean). Вы можете видеть, что тип свойств и их имена независимы. Обратите внимание на нижний регистр в имени свойства. (Это не случается, когда имя свойства начинается с более чем одной большой буквы в строке.) Запомните, что имена методов, которые вы видите здесь (такие как методы чтения и записи), на самом деле произведены объектом Method, который может быть использован для вызова ассоциированного метода объекта.
Список public методов включает методы, которые не связаны со свойствами или событиями, такие как croak( ). Здесь все методы, которые вы можете вызвать программно для компонента (Bean), и построитель приложения может выбрать список всех, когда вы выполняете вызов метода, для облегчения вашей задачи.
Наконец, вы можете видеть события, передающиеся в слушатели, методы слушателей, и методы добавления и удаления слушателей. В общем, так как вы имеете BeanInfo, вы можете найти все, что важно для компонента (Bean). Вы можете также вызвать методы для этого компонента (Bean), даже если у вас нет другой информации, за исключением объекта (опять с помощью рефлексии).