Java Beans - FIS Incorporated

rangesatanskingdomΛογισμικό & κατασκευή λογ/κού

2 Δεκ 2013 (πριν από 3 χρόνια και 10 μήνες)

79 εμφανίσεις

Java Beans


Notes taken from: The Awesome Power of Java Beans by Lawrence H. Rodrigues
(http://www.manning.com/Rodrigues) and from the Java Tutorials.





In general Java beans are:




Somewhat self
-
contained pieces of code that may contain predefined values
.



Communicate with the outside objects by creating an event (containg relevant information
and/or objects) and passing this event on to registered listeners



Provide methods for registering outside objects that want to be notified when bean events
occur, or

removing the notification when outside objects no longer want to be alerted
when events occur.

General run
-
time Java Bean construction


1.

A constructor with 0 arguments.

2.

The bean classes must be serializable, ie. Implement the Serializable interface

3.

The pro
perties, methods and events in the bean class must conform to design patterns.
Properties are updated by set… methods and obtained by get… methods.


The set/get methods for a simple property should be:



public void set<PropertyName>(propertytype value)


public propertyType get<PropertyName>


Set/Get methods for Indexed properties should be:




public void set<PropertyName>(int index, propertype value)


public propertyType get<PropertyName>(int index)


Indexed property set and get methods may throw an Arr
ayIndexOutOfBoundsException.


Set/Get methods for array properties should be:



public void set<PropertyName>(propertyType value[ ])


public propertyType[ ] void get<ProperyType>()


The set methods for boolean properties are the same as the simple properti
ed by instead
of a get… method name it is a ‘is…’ method name:




public Boolean is<PropertyName>()


The propertyType references above can be a Java primitive


such as int, float, or an
Java class


such as Vector, String, JFrame, etc.



4.

Contain methods

for registering target objects that want to be notified when bean events
occur, and deregistering when target objects no longer want to be notified when events
occur.


Usually more than one target object can be registered for receiving bean events.
Howeve
r, it is possible that the bean should only notify one target for the event.


For multiple targets a vector is used to hold the targets, and methods add or remove the
targets



Vector listeners = new Vector();





public void addActionListener(ActionListen
er target){



listeners.addElement(target);


}



public void removeActionListener(ActionListener target){



if (!listeners.isEmpty()) listeners.removeElement(target);


}



For beans allowing only one target the vector is not needed and the addEvent method

must throw an exception if more than one target tries to register.




public void addActionListener(ActionListener target) throws
java.util.TooManyListernersException{








}



5.

Information is passed from the bean (source) to a destination (target) by cr
eating events.


public class MyEvent extends java.util.EventObject (or subclass of EventObject){


public MyEvent(Object sourceObject, int event id, ….) {



….


}


// all set/get methods


// any other utility methods

}



6.

One or more event listeners are cre
ated to allow passing the event to the target. Each
event listeners can have one or more methods but are coded ‘empty’ .(code provided by
the target).


public
interface

MyEventListener extends java.util.EventListener{


public void processMyEvent(MyEvent
myEvent);


public void doSomethingElseWithMyEvent(MyEvent myEvent);




7.

Methods in the bean are called as needed to create an Event object and pass it on to the
target listeners. It is best to create a copy of the target listeners prior to starting the
no
tification process.


public void fireEvent(){


if (listeners.empty()) return;


Vector copyOfListeners;


MyEvent myEvent = new MyEvent(….. ) // pass in all needed info
and/or use additional set or other methods to add info to event


synchronized(this) {



copyOfListeners = (Vector) listeners.clone();


}


for (Enumeration e = copyofListeners.elements(),
e.hasMoreElements();){



((MyEventListener)(e.nextElement()).processMyEvent(
myEvent);


}

}







8.

The bean classes,serialized objects and resources must b
e in a jar file

Psuedo Code Java Bean


Putting it all together looks something like the following:


public class SomeEvent extends java.util.EventObject (or subclass of EventObject){


public SomeEvent(Object sourceObject, ….) { // info to pass to event o
bject



….


}


// add additional set/get methods


// add any other utility methods

}


public
interface

SomeEventListener extends java.util.EventListener{

public void processSomeEvent(MyEvent myEvent);

public void doSomethingElseWithSomeEvent(MyEv
ent myEvent);





public class SourceBean implements Serializable // Serializable not needed if
superclass implements it an your code doesn’t do anything








// to make in non
-
serializable


public SourceBean(){


// empty constructor






}







public void addEventListeners (eventListener e){ // the eventListener is the
listener
interface




// add to vector



}



public void removeEventListener(eventListener e){




// remove listener from vector



}



public void fireEvent(…){




// if no l
isteners registered return




// create the event with all info to be passed




// create copy of listener vector




// for each registered listener, perform eventListener method and pass
event



}


Target (User of) Java Bean


1.

The target can implement logi
c in several ways to receive events generated by the
JavaBean. For example:


a. The target can implement the listener


public class Target
implements MyEventListener
{




}



b. The target can implement an adapter (a class that just implements the listener
interface


public class Target {


SourceBean sourceBean = new SourceBean();


// create the source
java bean

MyEventAdapter myEventAdapter = new MyEventAdapter( this); //
create the adapter

sourceBean.addMyEventListener(myEventAdapter); // register lis
tener
with source bean

Public void executeCommand(…){


// some logic to be
executed when source bean fires event




}





public MyEventAdapter implements MyEventListener{ // class used to catch
event


TargetBean targetBean;


public MyEventAdapter(T
argetBean targetBean){ // save object that is
to process event



this.targetBean = targetBean;


}


public void performMyEvent(MyEvent myEvent){ // called by source
and event object passed from source to adapter



targetBean.executeCommand(…);

// call

logic in target to
process event



}

}


c. The target can implement an anonymous inner class to implement interface
and process events


public class Target {


SourceBean sourceBean = new SourceBean();


// create the source
java bean

sourceBean.addMyEv
entListener (



new MyEventListener(){



// create the listener




public void processEvent(MyEvent me){





executeMyCommand(…);





….




}



}

}


2.

If the JavaBean is serialized, the java ‘instantiate’ command is used instead of ‘new’.


A class loader
is needed to load the serialized object. The instantiate command
can throw a ClassNotFoundException or IOException. The general code is:





try {

ClassLoader cl = (MyJavaBean.class).getClassLoader();





myJavaBean = (MyJavaBean).instantiate (cl, “MyJa
vaBean”);





myJavaBean.callMethodsAsNeeded(…..);


}

catch IOException(IOException ioe){ ….}

catch ClassNotFoundException(ClassNotFoundException cnfe){….}


If a serialized version of the bean class is not available the bean class is
instantiated the same

as ‘new’.




Serialization of a Java Bean


A Java Bean can be customized during application construction then saved with the
customized values. The bean could also be used during application execution and then
saved with updated values for later use. A be
an needs to be serializable (to be saved
externally and recallable with its values intact) as needed.



1.

The class must implement Serializable (not needed if superclass it is derived from
implements Serializable) or Externalizable


2.

Properties of beans that

should not be saved when a bean is serialized should be
defined with ‘transient’

transient int tempValue;

transient Object tempObject;

int saveValue;

object saveObject;


3.

If implemented as Serializable, and if needed the class implements
writeObject(Objec
tOutputStream out) and readObject(ObjectInputStream in)
methods to execute special serialization/deserialization logic. If no special logic
needed then these methods aren’t needed either.


private void writeObject(ObjectOutputStream out) throws IOExceptio
n{


saveValue = something;


out.defaultWriteObject(); // writes out all non
-
transient data

}


private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException{


in.defaultReadObject(); // read in stored object


if (saveValue ==
something) {





// do some reinitialization logic as needed


}




4.

If implemented as Externalizable the writeExternal(ObjectOutput oo) and
readExternal(ObjectInput in ) must be written


5.

Registered listeners must be checked when a bean is serialized to dete
rmine if they
are serializable, and when a bean is deserialized any listeners must be reregistered.


pivate void writeObject(ObjectOutputStream out) throws IOException{


for (Enumeration e = listeners.elements(); e.hasMoreElements();){



SomeListener someL
istener = (SomeListener).e.nextElement();



if (someListener instanceof Serializable){




serListeners.addElement(someListener); //serListeners
vector previously defined



}


}


out.defaultWriteObject;

}



private void readObject(ObjectInputStream in) t
hrows IOException,
ClassNotFoundException{


in.defaultReadObject(); // read in stored object


for (Enumeration e =serListeners.elements(); e.hasMoreElements();){



SomeListener someListener = (SomeListener).e.nextElement();



addSomeListener(someListener
); // reregister listener


}

}



6.

When a bean is instantiated from a serialized prototype or class file and the object is
a GUI (visible) object, the addNotify() method is invoked. Provide an override method
is special logic is needed.


public void addNoti
fy(){


super.addNotify(){


// some special logic if needed


if (Beans.isDesignTime()){






}


}



7.

To ensure that a serialized bean is compatible with the current class, versioning is
used. A utility program is used to create a version number (long) can b
e assigned to
the bean during bean coding to unique identify that version of the code.


a.

Type the command “serialver

show” to start the utility

b.

Type in the class name of the bean and click show

c.

Copy (cut and paste) the generated version number into the b
ean java code.


Implementing the PropertyChange Event


1.

A property can be ‘bound’ such that when the property changes in source bean all
registered listeners in target beans may be notified of the change.


2.

The property change is communicated by PropertyChan
geEvent object. It’s
constructor an methods are:


public PropertyChangeEvent(Object source, String propertyName, Object
oldValue, Object newValue)

pce.getPropertyName()

pce.getOldValue();

pce.getNewValue();


Note that primitive Java property types (eg int,

float, etc.) must be converted to
corresponding wrapper classes (Integer(), Float(), etc.).


3.

A PropertyChangeSupport object is used to record listeners, with the constructor
typically being passed the creating object.


PropertyChangeSupport pcsNotifier =
new PropertyChangeSupport(this);


4.

The source bean registers/deregisters listeners


public void addPropertyChangeListener(PropertyChangeListener pce){


pcsNotifier.addPropertyChangeListener(pce);

}


public void removePropertyChangeListener(PropertyChangeLis
tener pce){



pcsNotifier.removePropertyChangeListener(pce);

}


5.

The notifications are generally fired in the setter method


public void set<propertyName>(someType newValue){


someType oldValue = property;


pcsNotifier.firePropertyChange(propertyName, oldVa
lue, newValue); //
values in wrapper if primitive Java type


property = newValue;


// any other needed logic

}




6.

The target object will implement the PropertyChangeListener interface with just one
method to override.


public propertyChange(PropertyChang
eEvent pce){


if (pce.getPropertyName().equals(“xxx”) {



xxxValue = pce.getOldValue();


}

}



Implementing the VetoablePropertyChange Event


1.

A change to a constrained property in a source bean can be rejected by a target
bean. The use of the VetoablePrope
rtyChange is very similar to a PropertyChange.


2.

The source bean can implement a VetoableChangeSupport object passing itself in
the constructor and make available the following methods.


VetoableChangeSupport vcsNotifier = new VetoableChangeSupport(this);

Public void addVetoableChangeListener(VetoableChangeListener vcl){


vcsNotifier.addVetoableChangeListener(vcl);

}

public void removeVeoableChangeListener(VetoableChangeListener vcl){


vcsNotifier.removeVetoableChangeListener(vcl);

}


Specific properties ca
n also be constrained using methods:




void addVetoableChangeListener(String propertyName,
VetoableChangeListener listener);



void removeVetoableChangeListener(String
propertyName,VetoableChangeListener listener);


As an alternative, for each constrained

property a Bean can provide methods
with the following signature to register and unregister vetoable change listeners
on a per property basis:




void add<
PropertyName
>Listener(VetoableChangeListener p);




void remove<
PropertyName
>Listener(VetoableChang
eListener p);



3.

In the constrained properties setter method call the fireVetoableChange() method.


public void set<propertyName>(someType newValue){


try{



someType oldValue = property;



vcs.fireVetoableChange(propertyName, oldValue, newValue); //
value
s in wrapper if primitive Java type


catch (PropertyVetoException pve){



// display and/or log error, or any other required logic


}


property = newValue;


// any other needed logic

}



Or have the setter method throw the PropertyVetoException so ‘higher’

logic can
catch and process it.


4.

Both VetoableChangeSupport and PropertyChangeSupport can be implemented if
needed to both constrain and bind the property. Add the firePropertyChange()
method after the fireVetoableChange() method.


5.

The target bean will
implement the VetoableChangeListener interface with it’s one
method vetoableChange()


public void vetoSomePropertyChange(PropertyChangeEvent pce) throws
PropertyVetoException{


Propertytype newValue = (PropertyType) e. getNewValue();


// some logic to see
if new value acceptable or should be rejected


if (contraintsFailed)



throw new PropertyVetoException(“Error msg”, e); // rolls back
change

}


Each contrained property must have a method as written above.



Building BeanInfo classes


1.

BeanInfo classes ca
n be built from scratch or some tools build automatically build the
skeleton for you.


2.

Naming convention must be <ClassName>BeanInfo.


3.

To build a BeanInfo class, extend SimpleBeanInfo (which implements BeanInfo
interface) and override appropriate methods.


4.

The beans API provides classes to describe the properties, methods and events the
bean exposes. They are


a.

PropertyDescriptor

i. IndexPropertyDescriptor (subclass of PropertyDescriptor)

b.

MethodDescriptor

c.

EventsetDescriptor

d.

BeanDescriptor


5.

FeatureDescriptor
class is the base class for feature descriptor classes that have
methods to set and get information about a feature.


6.

The BeanInfo interface specifies several methods to fetch feature descriptor objects
and the bean icon.


a. getBeanDescriptor()


returns
a BeanDescriptor (information about the bean in
general)

b. getMethodDescriptors() returns MethodDescriptor[] (array of info about the
methods)

c. getPropertyDescriptors() returns PropertyDescriptor[] (array of info about the
bean properties)

d. getEventSe
tDescriptors() returns EventSetDescriptor[] (array of info about the
bean events)

e. getIcon()


(the SimpleBeanInfo class provides loadImage(String
resourceName) so use loadImage in getIcon())



7.

Within each method above you code the construction of the fe
ature descriptor objects


8.

If the run
-
time class inherits features from it’s superclass, you can use
additionalBeanInfo() method to fetch BeanInfo object of another class. (It is not done
automatically)


9.

Steps in building a BeanInfo class


a.

Create a BeanInfo

source file using <ClassName>BeanInfo extending
SimpleBeanInfo or any other BeanInfo class that implements BeanInfo
interface or subclass of SimpleBeanInfo

b.

Implement getBeanDescriptor() and provide code to create a BeanDescriptor

c.

Implement (optional) getP
ropertyDescriptors() and provide code to create
array of PropertyDescriptors and IndexedPropertyDescriptors

d.

Implement (optional) getMethodDescriptors() and provide code to create
array of MethodDescriptors

e.

Implement (optional) getEventSetDescriptors() and
provide code to create
array of EventSetDescriptors


Overview of Descriptor classes


1.

The base class of descriptors in FeatureDescriptor. Subclasses are:


a.

ParameterDescriptor

b.

MethodDecriptor (contains ParameterDescriptor)

c.

EventSetDescriptor (contains Method
Descriptor)

d.

BeanDescriptor

e.

PropertyDescriptor

i.

IndexPropertyDescriptor


2.

Most descriptor classes have setter (usually used by bean creator), getter and
Boolean (used by builder tools) methods.


3.

The main purpose of the BeanDescriptor class is to provide the b
uilder tool with bean
meta class.


a. Constructor are


BeanDescriptor(Class beanClass)


BeanDescriptor(Class beanClass, Class customizer)

b. Example


public BeanDescriptor getBeanDescriptor(){



BeanDescriptor beanDescriptor = new BeanDescriptor(movieClas
s,
ScreenCustomizer.class);



beanDescriptor.setDisplayName(“Movie setup”);



registerEditor(); // register the custom property editors



return beanDescriptor;


}


4.

The MethodDescriptor class provides info about a method


a.

Constructors are

MethodDescripto
r(Method methodObj) // typically for methods w/o arguments

MethodDescriptor(Method methodOjb, ParameterDescriptors
parameterDescriptors[]) // for methods w/ arguments

b.

Construction a MethodDescriptor


// create array with parameter data types

Class param
eterClasses[] = {list of parameter types used in method, eg.
Float.class, JFame, etc.};

// create the method object with the parameter array

Method setScreenMethod = (Movie.class).getMethod(“setScreen”,
parameterClasses); // uses introspection

// Provide
info about each parameter

ParameterDescriptor pdScreenWidth = new ParameterDescriptor(); //
parm 1

pdScreenWidth.setDisplayName(“Width of Screen”);

pdScreenWidth.shortDescription(“Width of the Screen… Max/Min are….
Default is….”);

ParameterDescriptor pd
ScreenHeight = ….. // parm 2…

// create array of parameter descriptors just defined

ParameterDescriptor[] pdScreen = {pdScreenWidth, pdScreenHeight};

// now create method descriptor using Method and parameter descriptor
array




MethodDescriptor mdScree
n = new MethodDescriptor(setScreenMethod,
pdScreen);


5.

The EventDescriptor class provides info about the events fired by a bean. There are
several different constructors depending on the number of events to be defined


a.

Constructor for a single event listene
r method uses design patterns to construct
an object

EventSetDescriptor(Class beanClass, String eventSetName, Class
listenerType, String listenerMethod) // single event Method




try {




EventSetDescriptor edStart = EventSetDescriptor (
movieSelector.clas
s, “select”, SelectListener, “selectPerformed”);

return new EventSetDescriptor[] {edStart};



catch(IntrospectionException ie) {….}





b.

Constructor for a multiple event listener methods

EventSetDescriptor(Class beanClass, String eventSetName, Class
listene
rType, String listenerMethodNames[], String
addListenerMethodName, String removeListenerMethodName)




try {




String methodNameList[] =
{“movieSelected”,”movieDeselected”};

EventSetDescriptor edStart = EventSetDescriptor (
movieSelector.class, “movie”,
movieListenerClass,methodNameList, “addMovieListener”,
“removeMovieListener”);

return new EventSetDescriptor[] {edStart};



catch(IntrospectionException ie) {….}






c.

Constructor using the reflection API

EventSetDescriptor(String eventSetName, Class list
enerType, String
listenerMethodNames[], Method addListenerMethod, Method
removeListenerMethod)




try {




Class args[] = {MovieEvent.class};




Method movieStart =
MovieListener.class.getMethod(“startMovie”, args);




Method movieStop =
MovieListener.cla
ss.getMethod(“stopMovie”,args);




Method methods[] = {movieStart, movieStop};


Class args[] = {MovieListener.class};




Method addMovieListener =
Movie.class.getMethod(“addMovieListener”, args);




Method removeMovieListener =
Movie.class.getMethod(“remov
eMovieListener”,args);


EventSetDescriptor ed = EventSetDescriptor ( “movie”,
movieListener.class,methodNameList, methods,
addMovieListener, removeMovieListener);

return new EventSetDescriptor[] {ed};




catch(NoSuchMethodException nsme) {….}

catch(Intro
spectionException ie) {….}




d.

Constructor using the reflection and beans API allows the inclusion of information
about listener method arguments.

EventSetDescriptor(String eventSetName, Class listenerType,
MethodDescriptor listenerMethodDescriptors[], Meth
od
addListenerMethod, Method removeListenerMethod)


try {


Class args[] = {MovieEvent.class}; // the event class


ParameterDescriptor pd1 = new ParameterDescriptor(); // the
parameters within the event class


pd1.setShortDescription(“…..”);


ParameterD
escriptor[] startDescriptor = {pd1};




ParameterDescriptor pd2 = new ParameterDescriptor();


pd1.setShortDescription(“…..”);


ParameterDescriptor[] stopDescriptor = {pd2};



Method startMethod = MovieListener.class.getMethod(“start”,
args); // the event

listener method


MethodDescriptor startMd = new MethodDescriptor(startMethod,
startDescriptor);



Method stopMethod = MovieListener.class.getMethod(“stop”,
args); // the event listener method

MethodDescriptor stopMd = new MethodDescriptor(stopMethod,
st
opDescriptor);


MethodDescriptor movieMd[] = {startMd, stopdMd}; // create arry
of event listener method descriptors


Args = new Class[] {MovieListener.class};

Method addMethod =
Movie.class.getMethod(“addMovieListener, args); // create methods for
add/
remove

Method removeMethod =
.class.getMethod(“removeMovieListener, args);



EventSetDescriptor esd = new EventSetDescriptor(“movie”,
MovieListener.class, movieMd,addMethod, removeMethod);


return new EventSetDescriptor[] {esd};




}

catch(NoSuchMethodExce
ption nsme) {….}

catch(IntrospectionException ie) {….}



6.

The PropertyDescriptor describes the properties of a bean. There are 3 constructors:


PropertyDescriptor(String propertyName, Class beanClass) throws
IntrospectionException;

PropertyDescriptor(String

propertyName, Class beanClass, String getterName,
String setterName) throws IntrospectionException;

PropertyDescriptor(String propertyName, String getterName, String setterName)
throws IntrospectionException;


The first constructor assumes design patterns

are being followed, the second
and three constructors explicitly name the getter/setters for the property.



7.

The IndexedPropertyDescriptor (a subclass of PropertyDescriptor) describes the
indexed properties of a bean. There are 3 constructors:


IndexedPro
pertyDescriptor(String propertyName, Class beanClass) throws
IntrospectionException;

IndexedPropertyDescriptor(String propertyName, Class beanClass, String
getterName, String setterName, String indexedGetterName, String
indexedSetterName) throws Introspect
ionException;

IndexedPropertyDescriptor(String propertyName, Class beanClass, Method
getter, Method setter, Method indexedGetter, Method indexedSetter) throws
IntrospectionException;




Class Hierarchy and BeanInfo Classes


1.

Beans created as subclass of oth
er beans (which have their own BeanInfo classes)
can have BeanInfo classes created in several ways.



a.

Use getAdditionalBeanInfo(). Useful if no overlap/conflict with
properties/methods/events between super and subclass.


public BeanInfo[] getAdditionalBean
Info(){ // append all the feature
descriptors from other classes to the current one


BeanInfo superclassInfo = new SuperClassBeanInfo();


BeanInfo[] infoArray = {superclassInfo};


return infoArray;

}


If the ‘parent’ bean does not belong to the classes i
n the bean’s class
hierarchy, the TargetInvocationException is raised at run time
(construction)


More than one BeanInfo object can be returned in the array. The lower
indexed items have precedence over higher indexed items.


Methods, properties, and/or ev
ents can be overridden or hidden in the
corresponding descriptor methods.


b.

Create a BeanInfo subclass of the superclass. Use the get…Descriptors to
obtain the superclass descriptors and add/modify as needed.



Updated BeanInfo Construction Checklist


1.

Creat
e a <ClassName>BeanInfo class, extending from either SimpleBeanInfo from
another BeanInfo (implementing either BeanInfo interface or subclass of
SimpleBeanInfo)


2.

Override get<Feature>Descriptor methods as needed.



Common updates



Display names



Hide pro
perty



Add short description



Set as expert property


Update feature specific information



Override getBeanDescriptor() if need to register




A customizer




Class/interface specific property editors



Override getPropertyDescriptor() if need to




Ex
pose specific properties




Set property as bound and/or constrained




Register the property specific editor




If getter and setter methods do not follow design patterns



Override getMethodDescriptors() to expose specific methods



Override getEventSetD
escriptors()




To expose specific events




If listener and registration methods do not follow the design
pattern



Override getDefaultEventSet() if there is a default event set



Override getDefaultPropertySet() if there is a default property



Override
getIcon() if there is an icon (loadimage()) to identify the bean




Bean Instantiation


1.

Beans should always be instantiated using the instantiate() method rather than
new. Instantiate() looks for serialized prototype (.ser) to load first and if not found
w
ill create the bean from the class file.


Try{


ClassLoader cl = (MyClass.class).getClassLoader();


myClass = (MyClass)Beans.instantiate(cl, “package.MyClass”);

catch(ClassNotFoundException cnfe){…}

catch(IOException ioe){…}




2.

To check the type of a seria
lized prototype, use the method isInstanceOf().


If (Beans.isInstanceOf(myClass, package.MyClass){…}


3.

getInstanceOf() will instantiate a bean


MyClass myClass2 = null;

myClass2 = (package.MyClass)Beans.getInstanceOf( beanobject,
package.MyClass)


4.

Design
time vs run time can be checked using isDesignTime()


If (Beans.isDesignTime()){…}


5.

Determining if the bean is in a GUI environment change be checked by
guiAvailable() or can be set using setGuiAvailable(). Useful for both design and
run time.


If (Beans.i
sDesignTime()){…}