![]() ![]() ![]() |
||||||||||||||||||||||||
INPRISE Online And ZD Journals Present:
JavaBeans is probably one of the most simplistic and powerful component APIs ever invented. Although the guts of a JavaBeans-compatible tool like JBuilder are fairly complicated, creating JavaBeans components in this environment (or even by hand) is easy for the programmer. JavaBeans are simply Java classes that follow a few basic programming patterns. In fact, most of your custom Java components may already be JavaBeans-compliant—or very close. The surprisingly small list of requirements for a simple JavaBeans component dictate that it must
These requirements aren't complex and don't require a vast knowledge of the JavaBeans API. You'll add a few optional classes, but they have nothing to do with your Bean code (we'll cover them later). And, in case you're wondering, the only difference between a visual user interface Bean and a non-visual Bean (such as a database connection widget) is that a visual Bean inherits from the Component class. As we mentioned, JavaBeans follow a few programming rules, defined in the JavaBeans 1.0 specifications. The rest of the JavaBeans API uses these patterns to do the real work. To give you a good background on the architecture of JavaBeans, we'll ignore JBuilder's JavaBean support in this article and focus on what happens behind the scenes with JavaBeans.
Core reflection and serialization are the keys You use the Introspector class, in the java.beans package, to perform classification and pattern matching to create an API for the component. The product from the Introspector is a BeanInfo object, which has all the component API information used to manipulate the Bean. The Bean designer conforms to the programming patterns and method signatures the Introspector recognizes. Serialization is the second reason JavaBeans are simple. You can manipulate JavaBeans as live objects in a Bean-aware IDE. This is far different from a standard IDE, which incrementally changes source code that will eventually be compiled to form the final product. Using a JavaBeans editor, you create and manipulate the components, then save their states. Within the final application, instead of code that sets up a component step by step, the state of configured components and their interconnections is restored. Serialization also means that you need not create a secondary definitions file for each component that describes to the IDE how to generate code for end-user programs.
All you have to do is ensure that you're consistently following the rules in our list. Let's talk about the rules.
Default class constructor A default constructor is one of the primary things we find missing from most custom components. Designers often create class constructors that accept most of the configuration data as parameters. There's nothing wrong with this one-stop, one-line construction when coding by hand, but you also need to account for the Bean tool. A Bean will often be manipulated in the context of a design tool, as well as being hand-coded.
Implement java.io.Serialiazable The Serializable interface has no methods to implement, so there's nothing more to do for simple components. The Serializable interface is a marker interface that acts as a security pass—it simply allows the implementing class to be serialized. You'll want to watch out for a couple of things when designing serialized components. Static member variables aren't serialized, so don't use statics to store persistent data in a Bean. In addition, when converting a class to be serializable, you must identify any object member variables that don't need to be serialized. Non-serialized members require an initial state each time the object is reloaded. These members are called transient because they don't keep their states between executions. Transient members' definitions are prefixed with the keyword transient, which prevents serialization. For example, you'd use the transient modifier in a password dialog box, which should always start with blank entries and force the user to enter a complete password.
JavaBeans design signatures
The background method could set a color parameter called background or perform an action on anobject with a color property. To alleviate such ambiguities, JavaBeans components should follow simple naming rules and programming patterns that we collectively call JavaBeans design signatures. Design signatures fall into two categories: property access and events. All other class methods are considered actions on the component. See Table A for the current list of signatures. Using a simple property access design signature, the background color property access methods would look like this:
Table A:
With the design signatures in Table A, you can use the Core Reflection classes to locate matching types and names of the set/get pair. In the previous code snippet, the get and set methods would be matched by their method names and the common type. The result is a background property of type Color, which can be represented in an IDE's property sheet. The actual code to perform the design-signature parsing and classification tasks is in the Introspector class, which is part of the Java reference platform. As a result, you can apply the rules consistently for all Java implementations. Using method signatures is incredibly simple—no interface classes to implement, no specialized classes to inherit, and no special calls to register methods as property accessors. Best of all, method signatures are completely human-readable! Java 1.1 components also follow the design rules, so new JavaBeans are also consistent with Java. As you can see in Table A, there are several signature types, including simple, Boolean, and array. Two very useful types—bound and vetoable—use the 1.1 event model to advertise changes to properties. The event used in both cases is a PropertyChangeEvent. Since PropertyChangeEvent is part of the java.beans package, few people without an interest in JavaBeans have any idea of its existence. We believe this is one of the most important additions to the Java 1.1 API. PropertyChangeEvent can significantly reduce the coupling between components. As you know, coupling between classes is something to be avoided. With a property change event, classes (not just Beans) don't need application-specific code to notify a class that depends upon changes. You use vetoable events like bound events, except that event listeners can veto a property change. The primary use of a vetoable property is to add change-control management to a generic component without inheritance. Instead of creating a subclass of a component that limits input to a specific range of values, you create a component that fires a property change event to registered vetoable listeners. If a listener decides the new property value is out of range, it throws a PropertyChangeVetoException, which propagates back to the class that's attempting the change. There are also events and general methods. For events, we have a few more signatures that the Introspector class uses to recognize both event sources and event listeners. Methods not classified as a property access or an event are classified as special methods for the component.
JavaBeans and the delegation event model The delegation model is powerful because of its ability to reduce class coupling. Since listeners are interfaces, the listener class is an abstract part of another class. An even more powerful abstraction using the delegation model is to entirely avoid implementing the listener interface within application-specific classes. Instead, a class implementing the listener—called an external event adapter—acts as the glue to map events to specific objects and methods. For example, a target class's start() method can be called in an external event adapter from a class that implements a MouseListener. This is better than adding the Listener interface to the target class. Bean tools use external event adapters as the primary method to connect components, because the adapter can be generated on the fly and added to a running application. When the application is serialized, the adapters are serialized too, preserving the object relationship of event connections to be restored in the final running application. The alternative is to implement the listener in a new version of an existing class. Because you'd prefer that the design tool stay out of your custom code, external event adapters are superior. When processing events from a component or a group of components in a panel or window, a good rule of thumb is to never implement a listener in any class derived from AWT components. Instead, use inner classes to implement listeners or override the processEvent() or process<EventType>() methods of the base component. Implementing a listener at the customized component (the level visible to a Bean tool) falsely advertises that the component listens to external events. Also, any component that generates a new event type or generates property change events must have add and remove methods for the supported event. The Introspector class uses these method signatures to determine what events the component generates.
Complex Beans Three classes are associated with changing how a Bean is viewed and edited in a Bean tool: the PropertyEditor class, the Bean Customizer class, and the BeanInfo interface. If the Bean has properties that are custom types or require special handling, you must add custom property editors by extending the PropertyEditor class. A property type that isn't a primitive or one of the supported class types, like Color or Font, needs a way of editing the property. Some Beans have special editing requirements that can't be accomplished through a property sheet—for example, changing the state of the Bean by manipulating several properties in a sequence. In such a case, you'll use a class extending the Customizer class to present a dialog box that performs special configuration tasks by manipulating a component directly. You create the BeanInfo object by implementing the BeanInfo interface in the type of object returned by the Introspector class. The BeanInfo describes the Bean's API. You can add further information to customize the display of properties and to add the icon that represents the Bean in a Bean-aware application. The methods in the BeanInfo all return a value. If an implemented method in a custom BeanInfo returns null, the value found by the Introspector class is used instead. Writing a BeanInfo is easy if only a couple of methods require overrides. Daniel Brookshier is the author of JavaBeans Developer's Reference and is a contributing author to Industrial Strength Java (Chapters 3 and 14). He's a speaker, Java consultant, and Java mentor for Weston Brothers Software Inc. Dan is also the creator of the Talk-Java and Drink-Java user groups. You can reach him at turbogek@cluck.com. Back to Top Back to Index of Articles Copyright © 1997, ZD Journals, a division of Ziff-Davis Inc. ZD Journals and ZD Jounals logo are trademarks of Ziff-Davis Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis is prohibited. |