Craig and other "DynaBeaners",

I implemented a class that is very similar to what you describe several
months ago and it completely changed the way I do things, for the MUCH
better.

I am just going to describe a bit of my experience hoping that some of
you find it useful.


<!-- Section for those that don't understand "why DynaBeans": -->
<unbeliever-section>

I was in the process of turning a framework I have been working on from
prototype into a production version. One of the lessons learned from the
prototype was that we spend a lot of energy moving values with names in
web applications. Values it names are things like:
  - Servlet request parameters;
  - ResultSet columns;
  - Bean properties;
  - XML element attributes;
  - and a big ETC.

A typical silly situation is the simple HTML data entry over a database
table, where everything (all HTML Form fields and bean properties)
follows the column names of the table and you end up making a load of
assignments by hand.

It is crazy. It should be simple to say "move the servlet request
parameters to the bean properties with the same name (ignoring case)
using this set of conversion rules". Same thing to move the data from
the bean into the database and all the way back too.

For the bits of the circuit where there is no name match, a name to
name map takes care of it.


The first obvious step is to get a common interface you can use to
represent (and wrap) things with names. Something like this:

  public interface INameMapper
  {
      public Object get(String name);
      public void set(String name, Object value);

      public int       count();
      public String[]  names();
      public boolean   hasField(String name);
  }

(Keep in mind that this is not exactly what I use. I am just
describing the idea.)


Then you find out that in a lot of simple cases your beans are not
doing more than work as temporary storage and you dream of having a
DynaBean (which I call Record).

</unbeliever-section>

<!-- Now, this is for believers too... -->

And then you find out that you can do a lot more with DynaBeans.

For me it turned useless most of the stuff in utility classes like the
BeanUtils and PropertyUtils.


Consider a conversion class like this:

    public interface Converter
    {
        public Object convert(Class destType, Object srcValue)
            throws ConversionException;
    }

Now, this idea is not original. You end up building an object that
implements it by aggregating many simple conversion rules. New needs
for a new conversion type, new simple rule.

You can even use such a thing for data formatting and to parse data
of different formats.


The interesting bit is when you combine the above converter with a
DynaBean.

Most projects I see at Jakarta work with introspection from the
outside, asking which is the type of each property or asking for each
property to be converted to a given type. And then you end up with
dreadful utility classes that look like this:

    interface SomeBeanWrapper
    {
        int getAsString(String propName);
        ...
        int getAsInt(String propName);
        ...
        double getAsDouble(String propName);
        ...
    }

But inside a DynaBean, you can make the "set()" method like this:

    public void set(String propName, Object value)
    // throws ConversionException but this is a "RunTimeException"
    {
        final Class  fieldType = fieldType(propName);
        final Object newValue  = m_myConverter.convert(fieldType, value);
        internalSet(propName, newValue);  // set the property
    }

(Again, this is a gross simplification.)

So, for a DynaBean with a converter you never have to care about the
type of the values you are assigning to it - you just have to care that
its converter is appropriate. The DynaBean knows its field types and
makes the correct calls to the converter.


Now, maybe you will ask:
 - And what if I want to move the values stored in a DynaBean into
   something else?

And what if you never have to?


For a really dynamic DynaBean the method "internalSet()" of the last
code snippet would place the value into some HashTable (actually I use
something different). But what if there is an implementation of the
same DynaBeanInterface that is a wrapper?

I use a RecordWrapper (my "DynaBean" is called "Record") to wrap
beans, ResultSets and other typical sets-of-typed-named-values.

In most cases it is even the same RecordWrapper class - the
implementation change occurs in an associated class which name
includes the word "Introspector". There just is a different
introspector for beans than for Resultsets.


Now, there is a case I do not use DynaBeans for:
> * A way to dynamically represent XML input data as a tree of Java
>   objects.

If this is for configuration stuff, I think it is overkill. But then
maybe it is not for configuration, since you have the Digester.

I must say I find the Digester a bit too hard to use and I build a
derivative of the very-nice-and-simple configuration from Avalon.

The alteration has all to do with Ant. I like the way it is so simple
to build Ant targets and the way Ant uses introspection and knows so
many "property" types in my target "bean".

I use the same light data structure that the Avalon stuff builds to
represent XML configuration files (via SAX) but I put a Configurator
in between to introspect and assign the values to my components a la
Ant - with introspection + data conversion work via the above
mentioned "RecordWrapper".


The Configurator and Converter ideas come from Peter Donald's work
on Ant's "Myrmidon" proposal (the Configurator is calls "Configurer"
there).


I would love to get some feedback on this stuff.


Have fun,
Paulo Gaspar

http://www.krankikom.de
http://www.ruhronline.de


> -----Original Message-----
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]]On Behalf Of
> Craig R. McClanahan
> Sent: Saturday, December 15, 2001 10:26 PM
> To: [EMAIL PROTECTED]
> Subject: [Design Discussion] DynaBean - JavaBeans with dynamic
> properties
>
>
> There's been a lot of interest, both here (COMMONS-DEV), on the Struts
> mailing lists, and elsewhere in the idea of a JavaBean-like thing where
> the set of properties can be dynamically defined.  If support for this was
> integrated into the BeanUtils package in Commons, we could also make the
> methods in BeanUtils and PropertyUtils treat the properties of these beans
> like they do for regular JavaBeans, and thus be able to leverage them in
> environments based on BeanUtils (such as Struts).
>
> The purpose of this email is to summarize a set of design requirements for
> discussion purposes, so we can coalesce on a design and then get it
> implemented.  For extra fun, I've thrown in a very-raw idea of what the
> APIs might look like -- but I'd like to have the group's agreement before
> turning that into code.
>
> Before embarking on the actual development of dynamic beans support, we
> should also do a release of BeanUtils with the current enhancements, to
> provide a stable starting point.
>
> Please let me know what you think!
>
>
> BACKGROUND:
>
> The purpose of the DynaBean design (I'm not firmly attached to the name,
> but kinda like it :-) is to support application programming designs based
> on JavaBeans design patterns, but where the static nature of JavaBeans
> themselves (i.e. the fact that the set of properties is fixed at compile
> time) is too restrictive.  Some typical use cases for such a capability:
>
> * A bean object that represents a Row from a JDBC ResultSet
>   (the names and types of the column properties cannot be known
>   in advance because they are based on the SELECT statement).
>
> * A way to construct and use "value objects" that extract the
>   properties of an EJB into a structure that can be utilized by a
>   presentation tier technology such as JSP pages, without having
>   to hand code the value object.
>
> * A way to capture *all* of the request parameters from a servlet
>   request as a single object.
>
> * A way to dynamically represnt XML input data as a tree of Java objects.
>
>
> DESIGN REQUIREMENTS:
>
> * Support a completely arbitrary set of properties and corresponding
>   values, with the ability to add and remove properties dynamically.
>
> * Support the ability to dynamically register the set of property
>   names that are allowed, and then enforce storing only those
>   property names.
>
> * Support the ability to register data types (Java classes) for each
>   property, along with the names, with automatic type checking.
>
> * Support for properties with scalar types, array types, and
>   "mapped" types (as currently supported in Beanutils).
>
> * Support "simple" and "indexed" property getters and setters
>   in a style similar to standard JavaBeans.
>
> * Support registration of property change listeners and broadcast
>   of property change events
>
> * Provide the basic DynaBean API as a Java interface, as well as a
>   convenience base class, so that applications can adopt it however
>   they wish.
>
> * Base implementation class should implement Serializable so that
>   DynaBeans can be serialized and deserialized (assuming that the
>   actual property values can be).
>
> * Transparently support DynaBean objects in the existing BeanUtils
>   and PropertyUtils classes of the Bean Utilities package.
>
> * To the maximum extent feasible, provide JavaBeans-like introspection
>   capabilities of the available properties.  May require an
>   IntrospectionUtils addition to the Beanutils package.
>
>
> CONCEPTUAL API:
>
> public interface DynaBean {
>
>
>     // ----------------------------------------------------------------
>     // Dynamic property configuration
>     // ----------------------------------------------------------------
>
>     void addDynamic(String name);             // Unrestricted type
>     void addDynamic(String name, Class type); // Restricted type
>     void removeDyanamic(String name);         // Remove property & value
>     void restrictDynamic(boolean restrict);   // Are property names
>                                               // restricted to registered
>                                               // ones?  (default=false)
>                                               // (can be changed)
>
>     // ----------------------------------------------------------------
>     // Property getters and setters.  Behavior on previously
>     // unknown property names depends on the restrict setting
>     // ----------------------------------------------------------------
>
>     // Does this bean have a property of the specified name?
>     boolean contains(String name);
>
>     // Getters return null on unknown property names
>     Object get(String name);                  // Simple
>     Object get(String name, int index);       // Indexed
>     Object get(String name, String key);      // Mapped
>
>     // Setters are allowed to set null unless property is native.
>     // Optionally throw IllegalArgumentException if type is restricted
>     // and the value argument is not assignment-compatible
>     void set(String name, Object value);      // Simple
>     void set(String name, int index,          // Indexed
>              Object value);
>     void set(String name, String key,         // Mapped
>
> }
>
>
> Craig McClanahan
>
>
>
>
> --
> To unsubscribe, e-mail:
> <mailto:[EMAIL PROTECTED]>
> For additional commands, e-mail:
> <mailto:[EMAIL PROTECTED]>
>


--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to