Page 1 of 1

Java Beans

PostPosted: 05 Mar 2019, 07:51
by Ursego
To see the keywords colored, save the following text in a text file and open it in a Java compiler (or in Notepad++ and select in the menu: Language > J > Java).

Code: Select all
// A Java Bean is a reusable software component that can be manipulated visually in a builder tool. A bean is not required to inherit from any particular base class or interface. Visible beans must inherit from java.awt.Component so that they can be added to visual containers, but invisible beans aren't required to do this. While beans are primarily targeted at builder tools they are also entirely usable by human programmers. All the key APIs such as events, properties, and persistence, have been designed to work well both for human programmers and for builder tools. Many beans will have a strong visual aspect, in both the application builder and in the final constructed application, but while this is common it is not required.

// JavaBeans are classes that encapsulate many objects into a single object (the bean). They are serializable (i.e. implement java.io.Serializable or java.io.Externalization interface), have a zero-argument constructor, and allow access to properties using getter and setter methods.

// In order to function as a JavaBean, a class must obey certain conventions about method naming, construction, and behaviour. These conventions make it possible to have tools that can use, reuse, replace, and connect Java Beans:
// ● The class properties must be accessible using get, set, is (can be used for boolean properties instead of get), to and other methods (so-called accessor methods and mutator methods) according to a standard naming convention. This allows easy automated inspection and updating of bean state within frameworks, many of which include custom editors for various types of properties. Setters can have one or more than one argument.
// ● The class should be serializable, i.e. implement the java.io.Serializable interface (java.io.Externalization has a specific purpose and is rarely used). There is no need to implement Serializable in your class if it is already implemented in a superclass. All fields but static and transient are serialized.
// ● The class must have a public default constructor (with no arguments). This allows easy instantiation within editing and activation frameworks. This constructor will be called when an object is "reconstituted" by the deserialization process.
// ● It's a good idea to override equals(), hashCode() and toString().

public class PersonBean implements java.io.Serializable {
   // Peroperties:
    private String name;
    private boolean deceased;

    // Getters & setters:
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public boolean isDeceased() { return deceased; }
    public void setDeceased(boolean deceased) { his.deceased = deceased; }

    // Overridden equals():
    @Override
    public boolean equals(Object another) {
        if (this == another) return true;
        if (another == null || this.getClass() != another.getClass()) return false;
        PersonBean that = (PersonBean) another;
        if (this.deceased != that.deceased) return false;
        return !(this.name != null ? !this.name.equals(that.name) : that.name != null);
    }

    // Overridden hashCode():
    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (deceased ? 1 : 0);
        return result;
    }

    // Overridden toString()
    @Override
    public String toString() { return "PersonBean{" + "name = '" + name + '\'' + ", deceased = " + deceased + '}';
}

// Test that bean:

public class TestPersonBean {
    public static void main(String[] args) {
        PersonBean person = new PersonBean();
        person.setName("Bob");
        person.setDeceased(true);

        // Result: "Bob [deceased]"
        System.out.print(person.getName());
        System.out.println(person.isDeceased() ? " [deceased]" : " [alive]");
    }
}

// The JavaBeans functionality is provided by a set of interfaces in the java.beans package:
// AppletInitializer      Methods in this interface are used to initialize Beans that are also applets.
// BeanInfo               Allows the designer to specify information about the events, methods and properties of a Bean.
// Customizer            Allows the designer to provide a graphical user interface through which a bean may be configured.
// DesignMode            Methods in this interface determine if a bean is executing in design mode.
// ExceptionListener      A method in this interface is invoked when an exception has occurred.
// PropertyChangeListener   A method in this interface is invoked when a bound property is changed.
// PropertyEditor         Objects that implement this interface allow the designer to change and display property values.
// VetoableChangeListener   A method in this interface is invoked when a Constrained property is changed.
// Visibility            Methods in this interface allow a bean to execute in environments where the GUI is not available.

// Types of Bean Properties:
// ● Simple         A single value whose changes are independent of changes in any other property.
// ● Indexed      A range of values instead of a single value.
// ● Bound         A change to the property results in a notification being sent to some other bean.
// ● Constrained   A change to the property results in validation by another bean. The other bean may reject the change if it is not appropriate.

// Implementing Indexed Properties:
// Indexed properties represent collections of values accessed, like an array, by index. The indexed property design patterns are:
// Methods to access the entire indexed property array:
public <PropertyType>[] get();
public void set<PropertyName>([] value);
// Methods to access individual values:
public <PropertyType> get(int index);
public void set<PropertyName>(int index, value);

// Events:
// ● Beans use events to communicate with other beans.
// ● A bean that is to receive events (a listener bean) registers with the bean that fires the event (a source bean).
// ● Builder tools can examine a bean and determine which events that bean can fire (send) and which it can handle (receive).

// Class java.util.EventObject:
// The root class from which all event state objects shall be derived. THE PURPOSE OF AN EVENT CLASS IS TO BE PASSED AS AN ARGUMENT TO A METHOD WHICH HANDLES THE EVENT. All Events are constructed with a reference to the object, the "source", that is logically deemed to be the object upon which the Event initially occurred upon.
public class EventObject extends Object implements Serializable
// It has the method getSource() which returns the object on which the Event initially occurred:
public Object getSource()

// Interface java.util.EventListener:
public interface EventListener
// A tagging interface that all event listener interfaces must extend.

// Each distinct kind of event notification is defined as a distinct Java method. These methods are then grouped in an interface inherited from EventListener. An event class (i.e. a descendant of EventObject) that wants to handle any of the set of events defined in a given EventListener interface should implement that interface. Example:
public class MouseMovedExampleEvent extends EventObject {
   // This class defines the state object associated with the event
   ...
}
interface MouseMovedExampleListener extends EventListener {
   // This interface defines the listener methods that any event listeners for "MouseMovedExampleEvent" events must support.
   void mouseMoved(MouseMovedExampleEvent e);
   // ...and more events...
}
class ArbitraryObject implements MouseMovedExampleListener {
   public void mouseMoved(MouseMovedExampleEvent e) { ...implementation... }
   // ...and more events...
}

// Information associated with a particular event notification is normally encapsulated in an "event state" object that is a subclass of EventObject. By convention these event state classes are given names ending in "Event". For example:
public class MouseMovedExampleEvent extends EventObject {
   protected int x, y;
   MouseMovedExampleEvent(java.awt.Component source, Point location) {
      super(source);
      x = location.x;
      y = location.y;
   }
   public Point getLocation() { return new Point(x, y); }
   public void translateLocation(int xDelta, int yDelta) { this.x += xDelta; this.y += yDelta; } // translates coords, for use when propagating up view hierarchy
}
// New subclasses of EventObject may be created simply to allow logical distinctions between event state objects of different types, even if they share all the same data. It's a simple "logical" event - it does nothing in addition to what its ancestor does; the significant information is the type of the event subclass (the same principle as exception classes):
public class ControlExampleEvent extends EventObject {
   ControlExampleEvent(Control source) { super(source); }
}

// Event Listener Registration:
// A bean class can fire off any type of event, including custom events. Events are identified by a specific pattern of method names:
public void add<ListenerType>(<ListenerType> eventListener)
public void remove<ListenerType>(<ListenerType> eventListener)
// The listener type must be EventListener interface or its descendant. By convention these interfaces are given names ending in "Listener". Invoking the add<ListenerType> method adds the given listener to the set of event listeners registered for events associated with the <ListenerType>. Similarly invoking the remove<ListenerType> method removes the given listener from the set of event listeners registered for events associated with the <ListenerType>. The add<ListenerType> and remove<ListenerType> methods should normally be synchronized methods to avoid races in multi-threaded code. An example of event listener registration at a normal multicast event source:
public interface ModelChangedListener extends EventListener {
   void modelChanged(EventObject e);
}
public abstract class Model {
   private Vector listeners = new Vector(); // list of Listeners

   public synchronized void addModelChangedListener(ModelChangedListener eventListener) { listeners.addElement(eventListener); }

   public synchronized void removeModelChangedListener(ModelChangedListener eventListener) { listeners.removeElement(eventListener); }

   protected void notifyModelChanged() {
      Vector listenersTemp;
      EventObject eventObject = new EventObject(this);
      // Must copy the Vector here in order to freeze the state of the set of EventListeners the event should be delivered to prior to delivery. This ensures that any changes
      // made to the Vector from a target listener's method, during the delivery of this event will not take effect until after the event is delivered:
      synchronized(this) { listenersTemp = (Vector)listeners.clone(); }

      for (int i = 0; i < listenersTemp.size(); i++) { // deliver it!
         ModelChangedListener modelChangedListener = (ModelChangedListener)listenersTemp.elementAt(i)
         modelChangedListener.modelChanged(eventObject);
      }
   }
}

// EVENTS IN JAVA - BEGIN .......
// Interface java.util.ActionListener:
// The listener interface for receiving action events. The class that is interested in processing an action event implements this interface, and the object created with that class is registered with a component, using the component's addActionListener method. When the action event occurs, that object's actionPerformed method is invoked:
public interface ActionListener extends EventListener {
   void actionPerformed(ActionEvent e); // is called when the associated object generates a action
}
// An argument of type ActionEvent is passed to every ActionListener object that registered to receive such events using the component's addActionListener method.
// Methods of ActionEvent class:
public Object getSource()         // Returns the object on which the Event initially occurred.
public String getActionCommand()   // Returns the command string associated with this action.
public int   getModifiers()         // Returns the modifier keys held down during this action event.
public long getWhen()            // Returns the timestamp of when this event occurred.
public String paramString()         // Returns a parameter string identifying this action event.

// For example, the Button fires an ActionEvent whenever the user presses it. The entire point of an event is to inform a listener that something has happened to a component in the GUI. An event includes all of the information that a listener needs to figure out what happened and to whom it happened (the what and who of the event). An event must give enough information to fully describe itself. That way, a listener can figure out what exactly happened and respond in a meaningful way.

// The ActionEvent includes methods for learning the action's command string, modifiers, and identification string. The getActionCommand() method returns the command string that indicates the event's intended action, such as print or copy (the what). The getSource() method returns the object that generates the event (the who).

// In order to receive an ActionEvent, a listener must implement the ActionListener interface and register itself with the component. Furthermore, a component must keep track of its listeners in order to notify them of an event.

// By using the ActionEvent example as a model, we can easily see the pieces necessary for a component to generate an event and a listener to listen for an event. At a high level, there are three pieces:
// @@@@@@@ 1. The component
// @@@@@@@ 2. The event class
// @@@@@@@ 3. The listener interface

// @@@@@@@ 1. The component:
// Components generate events. An event is a component's way of letting a listener know that something has happened. Therefore, a component must provide a mechanism to register and deregister event listeners. The component must also track its listeners and pass on the events to those listeners. The mechanics of registration/deregistration and tracking are left to the individual component. However, a component will normally have an addXXXListener and removeXXXListener for each type of event that it generates. Internally, the component may store a listener however it chooses; usually, however, components store listeners in a java.util.Vector or javax.swing.event.EventListenerList. To fire off an event to its listeners, the component simply loops through its list of listeners and passes the event to each listener by calling the listener's event dispatch method:
EventListenerList xxxListeners = new EventListnerList();
public void addXXXListener(XXXListener listener) { xxxListeners.add(XXXListener.class, listener); } // registers the event
public void removeXXXListener(XXXListener listener) { xxxListeners.remove(XXXListener.class, listener); } // unregisters the event
// When an event occurs, the component creates an event object and passes it to the fireXXX() method, where it is passed to the listeners:
protected void fireXXX(XXXEvent xxxEvent) { // fires the event
     Object[] listeners = xxxListeners.getListenerList();
     // Loop through each listener and pass on the event if needed:
     for (int i = 0; i < listeners.length; i+=2)  {
          if (listeners[i] == XXXListener.class) {
               // Pass the event to the listeners event dispatch method:
               ((XXXListener)listeners[i+1]).dispatchXXX(xxxEvent);
          }           
     }
}

// @@@@@@@ 2. The event class:
// The event holds all of the information necessary for a listener to figure out what happened. The information included is really event specific. Just think about the event carefully and design the event class to hold whatever information is necessary to fully describe the event to a listener. Events normally extend the EventObject class.

// @@@@@@@ 3. The listener interface:
// An event listener interface defines the methods used by a component to dispatch events. Each event type will have at least one corresponding dispatch method in a listener interface. A listener interface takes the following generic format:
public interface XXXListener extends EventListener {
     // Event dispatch methods:
     somethingHappened(XXXEvent e);
     somethingElseHappened(XXXEvent e);
     ...
}
// To listen for an event, a listener must implement the XXXListener interface and register itself with the component. When an event occurs, the component will call the proper dispatch method. The methods are defined in an interface so that any object can receive the event. As long as the listener implements the interface, the component will know how to dispatch the event to the listener.

// As you can see, there are dependencies between some of the pieces. The listener interface corresponds directly to the event. The event is necessarily the dispatch method's argument. The component corresponds directly with the event and listener. It needs to know about each so that it can create events, dispatch events, and register listeners. Unlike the other two pieces, the event object is independent. As a result, many components are free to fire off the event type. Furthermore, multiple interfaces may define methods to dispatch the event.
// ....... EVENTS IN JAVA - END

// JavaBeans Event Model:
// Beans use events to communicate with other Beans. A Bean that wants to receive events (a listener Bean) registers its interest with the Bean that fires the event (a source Bean).
// ● An object interested in receiving events is an event listener - sometimes called event receiver.
// ● An object that generates (fires) events is called an event source (or event sender).
// ● Event listeners register their interest of receiving events to the event source.
// ● Event source provides the methods for event listeners to call for registration.
// ● The event source maintains a list of listeners and invokes them when an event occurs.

// Registration of Event Listeners:
// ● Event listeners are registered to the event source through the methods provided by the event source:
//       * addXXXListener
//       * removeXXXListener

// Steps of Writing Event Handling:
// @@@@@@@ 1. Write Event class
//       * Create your own custom event class, named XXXEvent or use an existing event class
//       * There are existing event classes (i.e. ActionEvent)
// @@@@@@@ 2. Write Event listener class (Event handler or Event receiver)
//       * Write XXXListener interface and provide implementation class of it
//       * There are built-in listerner interfaces (i.e. ActionListener)
// @@@@@@@ 3. Write Event source class (Event generator)
//       * Add an addXXXListener and removeXXXListener methods, where XXX stands for the name of the event
//       * These methods are used by event listeners for registration
//       * There are built-in event source classes

// Steps of Adding Event Handling
// @@@@@@@ 4.Write a glue class
//       * Register event listener to the event source through addXXXListener() method of the event source.

// @@@@@@@ 1. Write Event Class
// ● We are going to use ActionEvent class which is already provided in JDK

// @@@@@@@ 2.Write Event listener class
// ● We are going to use ActionListener interface which is already provided in JDK
// ● We are going to write ButtonHandler class which implements ActionListener interface
public class ButtonHandler implements ActionListener {
   // Component that will contain messages about events generated:
   private JTextArea outputTextArea;
   // Creates an ActionListener that will put messages in JTextArea everytime event received:
   public ButtonHandler(JTextArea outputTextArea) { this.outputTextArea = outputTextArea; }
   // When receives action event notification, appends message to the JTextArea passed into the constructor:
   public void actionPerformed(ActionEvent e) { this.outputTextArea.append( "Action occurred in the Button Handler: " + e + '\n' ); }
}

// @@@@@@@ 3.Write Event source class (Event generator)
// ● We are going to use Button class which is event source class and is already provided in JDK
// ● Button class already has the following methods:
//       * addActionListener
//       * removeActionListener

// @@@@@@@ 4.Write a glue class:
// ● Create object instances
// ● Register event handler to the event source
public class ActionEventExample {
   public static void main(String[] args) {
      JFrame frame = new JFrame("Button Handler");
      JTextArea outputTextArea = new JTextArea(6, 80);
      // Create event source object:
      JButton button = new JButton("Fire Event");
      // Register an ActionListener object to the event source:
      button.addActionListener(new ButtonHandler(outputTextArea));
      frame.add(button, BorderLayout.NORTH);
      frame.add(outputTextArea, BorderLayout.CENTER);
      frame.pack();
      frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE frame.setLocationRelativeTo(null));
      frame.setVisible(true);
   }
}
// What Happens When an Event Occurs?
// Event source invokes event handling method of all Event handlers (event listener) registered to it - actionPerformed() method is invoked

// ####### Introspection

// Introspection is the automatic process of analyzing a bean's design patterns to reveal the bean's properties, events, and PUBLIC methods. This process controls the publishing and discovery of bean operations and properties. By default, introspection is supported by reflection, where you name methods with certain naming patterns, like set/getProperty() and addXXXListener().

// Builder tools discover a Bean's properties, methods, and events by introspection. Beans support introspection in two ways:
// ● By adhering to specific naming conventions, known as design patterns, when naming Bean features. For example, a builder tool, in introspecting your Bean, discovers two methods, getColor() and setColor(), infers that a property named color exists, and displays that property in a property sheet where it can be edited.
// ● By explicity providing property, method, and event information with a related Bean Information class. A Bean information class implements the BeanInfo interface

// ####### Bean Persistence

// A bean may CONTAIN other beans, in which case it should store away these beans as part of its internal state. However a bean should not normally store away pointers to EXTERNAL beans (either peers or a parent container) but should rather expect these connections to be rebuilt by higher-level software. So normally it should use the "transient" keyword to mark pointers to other beans or to event listeners. In general it is a container's responsibility to keep track of any inter-bean wiring it creates and to store and resurrect it as needed. For the same reasons, normally event adaptors should mark their internal fields as "transient".

// ####### Bean Persistence in XML

// XMLEncoder Class:
// ● Enable beans to be saved in XML format
// ● The XMLEncoder class is assigned to write output files for textual representation of Serializable objects
XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(new FileOutputStream("Beanarchive.xml")));
encoder.writeObject(object);
encoder.close();

// XMLDecoder Class
// ● XMLDecoder class reads an XML document that was created with XMLEncoder:
XMLDecoder decoder = new XMLDecoder(new BufferedInputStream(new FileInputStream("Beanarchive.xml")));
Object object = decoder.readObject();
decoder.close();

// Example: SimpleBean
import java.awt.Color;
import java.beans.XMLDecoder;
import javax.swing.JLabel;
import java.io.Serializable;

public class SimpleBean extends JLabel implements Serializable {
   public SimpleBean() {
      setText( "Hello world!" );
      setOpaque( true );
      setBackground( Color.RED );
      setForeground( Color.YELLOW );
      setVerticalAlignment( CENTER );
      setHorizontalAlignment( CENTER );
   }
}

// Example: XML Representation:
<?xml version="1.0" encoding="UTF-8" ?>
<java>
   <object class="javax.swing.JFrame">
      <void method="add">
         <object class="java.awt.BorderLayout" field="CENTER"/>
         <object class="SimpleBean"/>
      </void>
      <void property="defaultCloseOperation">
         <object class="javax.swing.WindowConstants" field="DISPOSE_ON_CLOSE"/>
      </void>
      <void method="pack"/>
      <void property="visible">
      <boolean>true</boolean>
      </void>
   </object>
</java>