This package provides the classes that define the model portion of the ModelObjects Frameworktm. The primary classes of interest are ModelObjectAdapter, ModelDescriptor, and ModelAspectAdapter, and ModelAspectId.

ModelObjectAdapter presents a uniform interface to application model objects. It has a reference to a ModelDescriptor that describes the visible aspects of the model, and a reference to the adapted model object, as shown in the figure below. Within the ModelObjects framework, the term aspect means approximately the same thing as property in JavaBeanstm, but the implementation of aspects is more flexible.

        +------------------------------------------------+
        | ModelObjectAdapter                             |
        |                                                |
        |  Object getAspectValue(ModelAspectId)          |
        |  void   setAspectValue(ModelAspectId, Object)  |
        +----------+------------------------+------------+
                  /                          \
                 /                            \
       +--------+---------+            +-------+----------+
       | ModelDescriptor  |            | Object  (model)  |
       +-------+----------+            +------------------+
               |
     +---------+----------------+
     | { ModelAspectAdapter }   |
     |             \            |
     |         ModelAspectId    |
     +--------------------------+

ModelObjectAdapter is a concrete class that can be used without subclassing. Its ModelDescriptor defines the aspects of the model object that are manipulated by users of the ModelObjectAdapter. ModelDescriptors are class level metadata, much like instances of java.lang.Class. They describe an application model class in terms of ModelAspectAdapters.

ModelObjectAdapter follows a form of the Adapter design pattern where the actual work of adapting the model object's interface to the framework is delegated to other objects (ModelDescriptors and ModelAspectAdapters).

ModelDescriptor is a concrete class that can be used without subclassing. It also provides static methods to implement a simple registry of ModelDescriptors that can be looked by Class.

ModelDescriptor uses a Factory Method to create ModelObjectAdapters for model instances. In this way, subclasses of ModelDescriptor that override the factory method can return instances of customized subclasses of ModelObjectAdapter for special purposes.

ModelAspectAdapter is an abstract class that must subclassed for each aspect of a model class adapted by the framework. It is used to provide a uniform interface, and somewhat enhanced behavior, for each exposed aspect of the model. Like ModelDescriptor, it represents class level metadata that does not store any state particular to individual model instances. ModelAspectAdapters are identified by ModelAspectIds.

ModelAspectAdapter follows a form of the Adapter design pattern. The abstract class defines abstract methods that are used within the framework, and concrete implementations of these methods are defined in terms of the interfaces of the adapted model classes. In the case of ModelAspectAdapters, the adapted model objects are passed as parameters to methods, rather than stored as instance variables.

ModelAspectIds are used to identify model aspects. They are used rather than Strings for expressive clarity, type safety, and for enhanced runtime performance (they make better hashkeys than Strings). ModelAspectId provides a static method for finding (or creating if necessary) a ModelAspectId for a given aspect name provided as a String. It ensures that there is only one instance of ModelAspectId for a given aspect name.

Advanced Uses

Aspects are more flexible than properties. It is possible to define a ModelAspectAdapter for anything that can be computed using the model class's interface. Moreover, ModelAspectAdapter implementations are not restricted to using only selected public methods of model classes, but can use all of the Java language to implement the interface.

Additional custom behavior can be added to subclasses of ModelObjectAdapter. For example, performing special data validation or even reading and writing to a relational database. In many cases, extended behavior is implemented by delegation to another class that encapsulates that behavior.

It is possible to define new model aspects with storage for aspect values outside the model object. Typically this is done by using a subclass of ModelObjectAdapter with additional instance variables for extended aspect storage, and a subclass of ModelDescriptor that returns instances of the ModelObjectAdapter subclass from its factory method. The ModelAspectAdapters that define these advanced aspects will have access to both the model object and the ModelObjectAdapter to implement their behavior.

Cached computed aspects can be implemented using the same approach as other "extra" attributes, as described above. For example, a model object representing a database row might have a stored field for a foreign key value, but no storage for the model object denoted by that foreign key. Storage for the referenced object can be provided in the ModelObjectAdapter, and the ModelAspectAdapters for foreign key aspect and the referenced object aspect can be coordinated so that they never become inconsistent.

ModelDescriptor subclasses can maintain a strict 1-to-1 mapping between models objects and ModelObjectAdapters by making sure that there is only one active ModelObjectAdapter for a given model object at a time. In many cases it's not necessary to do this, but it may be necessary in cases where the ModelObjectAdapter provides extended aspect storage that could become inconsistent if the adapted model object was modified through a difference ModelObjectAdapter instance.