views:

75

answers:

3

I want to bind parameters of a ServletRequest to arbitrary domain objects. Params are available as a map of type

Map<String, String[]> // String = key, String[] = values

They should be converted and bound to the fields of the target object. Id like to have a method like this:

// definition: 
public void bind(Map<String, String[]>, T target)

// usage:
bind(request.getParameterMap(), domainObject);

What is the best way to bind request parameters to a domain object in a Java Servlet? What libs are available for this purpose or how would you write one?

A: 

You can use Java Refelection API for this. Assuming you have all the keys as attributes in your Domain object, with an appropriate data type.

Adeel Ansari
A: 

I'd say it depends on what kind of object the actual domainObject is. If it's a bean, you could use an reflection based automated bean populator such as my BeanPropertyController (it's free so give it a try! License is ASF2.0) to do the following:

/* Assumed parameter input:
 * a=hello
 * c=123
 * e=f,g,h
 * 
 * Matching bean:  
 */
public class ParamBean {
    private String a;
    private int c;
    private String[] e;
    /* + all the normal getters and setters you'd see in a bean */
}

/* somewhere in your servlet: */

BeanPropertyController bpc = BeanPropertyController.of(ParamBean.class);

for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
    bpc.mutate(entry.getKey(),
               getNiceValue(entry.getValue(), bpc.typeOf(entry.getKey()));
}

ParamBean bean = bpc.getObject(ParamBean.class);

/* somewhere else in the class */

public Object getNiceValue(String[] objs, Class<?> desiredClass) {
    if (objs.length == 1) {
     Object o = objs[0];
     return convertString(o);
    } else {
     Object[] newObjs = Object[objs.length];

     for (int i=0;i<objs.length;i++) {
      newObjs[i] = convertString(objs[i]);
     }

     return (Object) newObjs;
    }
}

private Object convertString(String value, Class<> desiredClass) {
    if (Number.class.isAssignableFrom(desiredClass)) {
     Double d = null;
     try {
      d = Double.parseDouble(value)
     } catch (NumberFormatException e) {
      // Not of the desired type, do whatever you want
     }
     if (Double.class.isAssignableFrom(desiredClass)) {
      return d;
     } else if (Long.class.isAssignableFrom(desiredClass)) {
      return d.longValue();
     } else if (Integer.class.isAssignableFrom(desiredClass)) {
      return d.intValue();
     } // and so on...
    } else if (Boolean.class.isAssignableFrom(desiredClass)) {
     try {
      return Boolean.valueOf(value);
     } catch (NullPointerException e) {
      // Not of the desired type, do whatever you want
     }
    } else {
     return value; // or whatever your default type is
    }
}
Esko
For my use case the getNiceValue method would be the most interesting thing. I need something for the actual conversion from a flat map to a object structure.
deamon
Fair enough, updated code example. It may be buggy though, I'm currently far away from my home computer and had to use Notepad. Merry Christmas!
Esko
+1  A: 

Have you looked into the Spring MVC (http://springsource.org) framework at all? It provides binding functionality which you can use outside of Spring. Also, if you are not currently using another MVC framework, it's a good one to consider.

cjstehno