Joda System API

org.joda.property.impl
Class AbstractBean

java.lang.Object
  |
  +--org.joda.property.impl.AbstractModelElement
        |
        +--org.joda.property.impl.AbstractBean
All Implemented Interfaces:
Bean, Bean.Internal, java.lang.Cloneable, ModelElement, java.io.Serializable

public abstract class AbstractBean
extends AbstractModelElement
implements Bean, Bean.Internal

AbstractBean should be extended by classes in the application domain model. A coded bean should be used where functionality is required on the bean classes over and above simple get and set methods.

A AbstractBean subclass can override the default initialization of the Property objects. (The default initialization uses reflection to work out the properties.) A subclass can change the default by overriding initPropertyMap() and calling addProperty for each property required. For example:

 public class Person extends AbstractBean {
   private String iSurname = null;  // can't declare as final
   // no-args constructor used by Joda and application
   public Person() {
     super();
   }
   // public constructor used by application
   public Person(String surname) {
     iSurname = surname;
   }
   // public getter used by application
   public String getSurname() {
     return iSurname;
   }
   // public setter used by application, with example validation
   public void setSurname(String surname) {
     if (Character.isAlpha(surname) == false) {
       throw new IllegalArgumentException();
     }
     iSurname = surname;
   }
   // initialise (not really needed in this case as can be auto reflected)
   protected void initPropertyMap() {
     addProperty("surname");
   }
 }
 

A AbstractBean must define get and set methods for each property it wishes to expose. The get and set methods do not have to be public. This can enable useful behaviour, such as the ability to set a value in the constructor and not have a public set method (a wrapper). For example:

 public class Profile extends AbstractBean {
   private Person iPerson = null;  // can't declare as final
   // private constructor used by Joda
   private Profile() {
     super();
   }
   // public constructor used by application
   public Profile(Person person) {
     iPerson = person;
   }
   // public getter used by application
   public Person getPerson() {
     return iPerson;
   }
   // private setter used by Joda
   private void setPerson(Person person) {
     iPerson = person;
   }
   // other methods...
 }
 

Author:
Stephen Colebourne
See Also:
Serialized Form

Nested Class Summary
 
Nested classes inherited from class org.joda.property.Bean
Bean.Internal
 
Constructor Summary
AbstractBean()
          Constructor.
 
Method Summary
protected  void addDependency(Property property, Property derivedFromProperty)
          Add a Dependency from one property to another.
protected  void addProperty(java.lang.String propertyName)
          Add a property to the map using the standard approach.
protected  void addPropertyWrapper(java.lang.String propertyName)
          Add a property to the map using the 'wrapper' approach.
protected  void checkModifiable(Property property)
          Check whether a particular property is modifiable.
 java.lang.Object cloneDeep()
          Deep clone the bean.
 Bean cloneDeep(IdentityBasedHashMap clonedObjects)
          Clone this bean avoiding recursion.
 boolean equals(java.lang.Object object)
          Equals is implemented to perform a deep equality check on all properties.
 java.lang.Class getBeanType()
          Get the type of the Bean, which is the implementing class.
 Property getProperty(java.lang.String propertyName)
          Get a Property object by name
 java.util.Map getPropertyMap()
          Get the Map of properties.
 int hashCode()
          Get the hashCode for the bean.
protected  void initPropertyMap()
          Initialize the map of properties.
 java.lang.String toString()
          Get a debug string for the property.
 
Methods inherited from class org.joda.property.impl.AbstractModelElement
getAttribute, getAttributeCount, getAttributeMap, setAttribute
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface org.joda.property.ModelElement
getAttribute, getAttributeCount, getAttributeMap, setAttribute
 

Constructor Detail

AbstractBean

public AbstractBean()
Constructor.

Method Detail

getBeanType

public java.lang.Class getBeanType()
Get the type of the Bean, which is the implementing class.

Specified by:
getBeanType in interface Bean
Returns:
the bean's type

getPropertyMap

public java.util.Map getPropertyMap()
Get the Map of properties.

Specified by:
getPropertyMap in interface Bean
Returns:
the Map of Property objects, keyed by String property name
See Also:
Bean.getPropertyMap()

getProperty

public Property getProperty(java.lang.String propertyName)
Get a Property object by name

Specified by:
getProperty in interface Bean
Parameters:
propertyName - the name of the property to obtain
Returns:
the property, or null if none found
See Also:
Bean.getProperty(String)

initPropertyMap

protected void initPropertyMap()
Initialize the map of properties. Subclasses can override the default reflection behaviour by calling back to the addProperty methods.


addPropertyWrapper

protected void addPropertyWrapper(java.lang.String propertyName)
Add a property to the map using the 'wrapper' approach. This approach creates a property that will use reflection to callback to the bean's hand coded get and set methods.

With this approach the get/set methods are required and the property method is optional. The set method may be non-public if required. If it is omitted then tools (like XML parsers) cannot set the value of the property. For example:

 public class Person extends CodedBean {
   private String iSurname == null;
   // optional
   public StringProperty surname() {
     return (StringProperty) getProperty("surname");
   }
   // required
   public String getSurname() {
     return iSurname;
   }
   // can be non-public if desired
   public void setSurname(String surname) {
     checkModifiable(surname());
     Object oldValue = iSurname;
     iSurname = surname;
     surname().firePropertyValueChanged(oldValue, iSurname);
   }
 }

This approach is recommended if you wish to provide any kind of validation in the get/set methods. The methods are coded as normal. The only requirement is that the set method should call firePropertyValueChanged() when the value changes. The approach can be mixed with the standard one in the same bean if required.


addProperty

protected void addProperty(java.lang.String propertyName)
Add a property to the map using the standard approach. This will use its own data area to store the value, following the normal rules defined in the JodaFactory.

With this approach the property method is required and the get/set methods are optional. The get and set methods (if any) must delegate to the property method. No instance variables are defined, for example:

 public class Person extends CodedBean {
   // required
   public StringProperty surname() {
     return (StringProperty) getProperty("surname");
   }
   // optional
   public String getSurname() {
     return surname().get();
   }
   // optional
   public void setSurname(String surname) {
     surname().set(surname);
   }
 }

This approach is best when you have a simple get/set method without validation. (If a factory based approach is acceptable, then these methods can be auto generated at runtime by JodaFactory from an interface - see JodaFactory). This approach can be mixed with the wrapper one in the same bean if required.


addDependency

protected void addDependency(Property property,
                             Property derivedFromProperty)
Add a Dependency from one property to another. This method need to be called for properties which derive their value from other properties.

Parameters:
property - the property
derivedFromProperty - the property it derives it's value from

checkModifiable

protected void checkModifiable(Property property)
Check whether a particular property is modifiable. This should be called in hand coded set methods before setting the value

Parameters:
property - the property to check

equals

public boolean equals(java.lang.Object object)
Equals is implemented to perform a deep equality check on all properties.

Specified by:
equals in interface Bean
Overrides:
equals in class java.lang.Object
Parameters:
object - the object to check against
Returns:
true if equals

hashCode

public int hashCode()
Get the hashCode for the bean. Beans should not really be used as keys in HashMaps as they are mutable. (Keys should be immutable, as if the value changes, the HashMap will fail to return the value). Thus this method always returns one (zero generally refers to null).

The effect of this is inefficient HashMaps. The HashMap will fall back to using equals() when the hashCode() is the same. Thus, as long as the objects are not changed, the Map.get() should work.

Specified by:
hashCode in interface Bean
Overrides:
hashCode in class java.lang.Object
Returns:
a suitable hashcode
See Also:
Object.hashCode()

cloneDeep

public java.lang.Object cloneDeep()
Deep clone the bean.

Specified by:
cloneDeep in interface Bean
Returns:
deep clone of this bean
See Also:
Object.clone()

cloneDeep

public Bean cloneDeep(IdentityBasedHashMap clonedObjects)
Description copied from interface: Bean.Internal
Clone this bean avoiding recursion.

Specified by:
cloneDeep in interface Bean.Internal
Parameters:
clonedObjects - the map of original element to cloned element
See Also:
Bean.Internal#cloneDeep(IdentityBasedHashMap)

toString

public java.lang.String toString()
Get a debug string for the property.

Specified by:
toString in interface Bean
Overrides:
toString in class java.lang.Object
Returns:
debug string, never null

Joda System API

Copyright © 2001-2003 Stephen Colebourne. All Rights Reserved.