Hi,

I was very intrigued by the text I read on the BeanUtils Component webpage:

[...] It is natural to then access these [bean getter and setter] methods
directly, using calls to the corresponding getXxx and setXxx methods.
However, there are some occasions where dynamic access to Java object
properties (without compiled-in knowledge of the property getter and setter
methods to be called) is needed. [...]

I've been working on a small set of interfaces that should make it easier to
access properties of Java objects in a generic fashion:

* GetMethod and SetMethod: abstraction of getter and setter methods, have an
invoke method
* LinkInfo: allows querying of the name and available getters, setters.
* Linkable: objects that implement this interface expose LinkInfo.

So, in short, Linkables expose their getters and setters in a uniform way.

With this I created an abstract LinkableBean class which hides / provides
implementations of the interfaces I mentioned:

* BeanGetMethod and BeanSetMethod: static inner classes that encapsulate
java.lang.reflect.Methods
* BeanLinkInfo: static inner class, uses introspection on the actual
(sub)Class object (check for getXXX, isXXX, setXXX) to build map of
BeanGetMethods and BeanSetMethods
* LinkableBean: implements Linkable so you can get the BeanLinkInfo.

All you need to do is extend LinkableBean by providing accessors following
the beans convention and they are exposed through LinkInfo. I also
implemented a linkable tree structure, you can implement linkable maps,
lists, struts.ActionForms...

I also provided a LinkableMapAdapter class (implements java.util.Map) for
Linkables that don't provide accessors on their object type interface. The
adapter deals with nested Linkables (a Linkable property within a Linkable)
by using keys with dot notation, e.g.
adapterInstance.get("person.adress.street").

To deal with types and type conversion, the Converter interface can be used.
It contains one method:

    Object convert(Object source, Class destinationType)

A Converter should implement a certain contract. It can use the Conversion
interface to implement certain points of this contract. An example of a
Converter is the TypeConverter which implements the following contract:

1. if source == null, return null
2. [IdentityConversion] if destinationType.isAssignableFrom(sourceType),
return source
3. [ValueOf Conversion] if destinationType implements a static factory
method with signature valueOf(sourceType) or valueOf(superclass of
sourceType), return destinationType.valueOf(source)

IdentityConversion.convert(source) just returns source.
ValueOfConversion.convert(source) encapsulates a java.lang.reflect.Method
that should be invoked with source as parameter.

The TypeConverter is plugged into the BeanSetMethod; it can be used wherever
some type flexibility is desired of course.

The contract that TypeConverter implements was not randomly chosen. Note
that the majority of Java primitive wrapper classes implement 'valueOf'
factory methods, e.g. Integer.valueOf(String). So setting an int (primitive)
property with a String through a BeanSetMethod can happen without extra
coding effort, knowing that java.lang.reflect.Method and TypeConverter apply
'automatic' wrapping of primitives.

Using the TypeConverter in BeanSetMethod allows you to use whathever other
(compound) property types on a bean. As long as the destination type
implements the appropriate static factory methods, it can be set by a source
object it recognizes.

Finally, I provided some classes that operate on Linkables:

* abstract Linker class: provides ways of creating Links (mediator between
two Linkables) and a LinkManager for managing those Links.
* Copier extends Linker: can copy properties of a source Linkable into
matching properties (by name) of a destination Linkable.
* DeepCopier extends Copier: performs a deep copy, when you want nested
Linkables themselves to be deep copied instead of the source reference being
set on the destination.

Maybe this would be an easy-to-use way of dealing with properties on
objects?

Jensie.

Reply via email to