You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Mark Rines <mr...@inforise.com> on 2005/01/18 23:16:03 UTC

BeanUtilsBean setProperty conversion not allowing String[] to Object

I'm having a hard time understanding the philosophy behind
org.apache.commons.beanutils.BeanUtilsBean's
setProperty(Object bean, String name, Object value) method. There seems to
be a design decision to eliminate
the inheritance of arrays from Object. I looked through bugzilla on 
issues.appache.org and found id=16525 and 32874 interesting and somewhat 
related but I guess I still don't get it.

Here is the background:
 I'm using commons-beanutils-1.7.0 in a Struts 1.2.x application.

 My program has the following form (bean):

  public class MyForm extends ActionForm{

  Object o = null;

  public void setObject(Object toSet){
   o = toSet;
  }

  public Object getObject(){
   return o;
  }

Given that an array is an Object, you should be able to:

  String t = "test";
  String[] sa = {t,t};
  MyForm myForm = new MyForm();

  HashMap map = new HashMap(1);
  map.put("object",sa);
  BeanUtils.populate(myForm,map);
  //myForm.setObject(sa);  // cause this line works

you then should be able to successfully compile and execute:

  String[] sa2 = (String[])myForm.getObject();
  assert(sa[0].equals(t));
  assert(sa[1].equals(t));

Instead I'm getting no sa[1] from getObject() and o is now a simple String
with value "test".

My discovery:

 BeanUtilsBean.setProperty reflects the myForm.setObject method and assumes
property Object is scalar;
 which is an invalid assumption as Object could be an array. It appears that
setProperty then
 "converts" the sa String array to a simple String using the first element
of the array (hardcoded 0) and
 drops the rest of the array. This is lossy at best and quietly violates
"data-in equals data-out".

 This lossy behavior can be traced to lines 1003-1005 in BeanUtilsBean's
setProperty method as follows:

             } else if (value instanceof String[]) {
                newValue = getConvertUtils().convert(((String[]) value)[0],
                                                type);

Again, the above code appears to render invalid the inheritance of arrays
from Object and precludes me from writing a Converter for String[] to
Object.

Suggested fix:

 BeanUtilsBean.setProperty should reflect the named property's set method
and check if sa (the String[] argument) is
 an instanceof Object (the set method's parameter type) and simply pass the
array into the set method unchanged.

 What would be the impact of changing line 1003-5 in BeanUtilsBean from:

     } else if (value instanceof String[]) {
                newValue = getConvertUtils().convert(((String[]) value)[0],
                                                type);


 to something like:

            } else if (value instanceof String[] && !(value instanceof
type) ) {
                newValue = getConvertUtils().convert(((String[]) value)[0],
                                                type);

???

I realize the design allows for making my own Converter and registering with
ConvertUtils but it is not obvious to me
how I can circumnavigate the intrinsic assumption that Object is scalar.
Besides, adding conversions for common types
to their parents seems to add unnecessarily to maintenance costs, violate
the principles of OO and
limits the flexibilty of polymorphism.

I anxiously await work-arounds, debate, criticism, alternative solutions,
pointers, hacks, etc...

Mark Rines


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org