Building a better BeanProcessor

At the moment I’m coding up a ‘BeanMapper’. Something to automatically transform a ResultSet into a JavaBean object. (Why would you want to do this? Write and maintain less code will probably do as a worthwhile cause.)

The DBUtils Apache commons project has a BeanProcessor that does a basic job. It is good for a simple mapping, however it does not meet the following challenges:

  1. Inheritance – a ResultSet may map to different Objects of the same parent over different rows
  2. Aggregates – a ResultSet may contain the data to build some/all of the aggregate objects
  3. Multiple Objects – a ResultSet may contain the data for many objects in one row

Challenge #1 can occur whenever inheritance is used, Challenges #2 and #3 are linked with improving performance (though I’m finding it difficult to imagine a scenario for #3 right now).

As well as the challenges there are some improvements that may be made:

  • The current BeanProcessor mapping works with the JavaBean standard – getColumnName/setColumnName will map to columnname in the database. A solution that also works with Annotations and/or Object fields would be helpful.
  • Automatic name mapping of the object ‘standard’ (camelCase) to the database ‘standard’ (under_score) would also be helpful.
  • Since I’m a user of the Spring framework, something that I can use as a default RowCallbackHandler

So what would my ideal mapping solution look like in operation?

I would have JDBC DAO that maps a variable ResultSet automatically to a set of target classes…

public interface JellyDAO {
  public Jelly find(Long jellyId);
  public List<Jelly> find(FindRequest findRequest);
} 
public class JellyDAOJdbc implements JellyDAO {

  List<Class> targetClasses;
  List<Class> aggregateClasses;
  BeanMapper beanMapper;

  public jellyDAOJdbc() {
    // The ResultSet may contain data for 
    // any of the following target classes.
    targetClasses = new ArrayList<Class>();
    targetClasses.add(JellyBean.class);
    targetClasses.add(JellyCup.class);
    targetClasses.add(JellyCupAndSpoon.class);
    // The Target classes may contain the following classes
    // that may also come across in the ResultSet.
    aggregateClasses = new ArrayList<Class>();
    aggregateClasses.add(JellyAttribute.class);
    aggregateClasses.add(JellyCompany.class);
    //
    beanMapper = new BeanMapper(targetClasses, aggregateClasses);
  }

  private Jelly processResultSetRow(ResultSet resultSet) {
    // Map the ResultSet to a Jelly class.
    Jelly jelly = (Jelly) beanMapper.toBean(resultSet);
    return jelly;
  }

  private List<Jelly> finder() {
    // Obtain a ResultSet..

    // Loop through result set..
    {
      jellyList.add(processResultSetRow(resultSet));
    }

    return jellyList;
  }

}

The Jelly domain model might be something like…

public abstract class Jelly { 
  Long jellyId; 
  String jellyType; 
} 
public class JellyAttribute { 
  String name; 
  String value; 
} 
public class JellyCompany {
  String companyName;
  String address;
}
public class JellyBean extends Jelly { 
  String targetMarket;
  BigDecimal weight;
  JellyAttribute flavour; 
  JellyAttribute colour; 
  JellyCompany company;
}
public class JellyCup extends Jelly {
  String productName;
  BigDecimal volume;
  JellyAttribute shape;
}
public class JellyCupAndSpoon extends JellyCup {
  String spoonMaterial;
  BigDecimal spoonLength;
}
public class JellyRepository {
  public Jelly find(Long jellyId);
  public List<Jelly> find(FindRequest findRequest);
}

I would also have a database view or stored procedure with the following signature…

jelly_id, jelly_type, target_market, product_name, 
spoon_material, spoon_length, cup_volume, flavour_name, 
flavour_value, colour_name, colour_value, company_name, 
company_address, shape_name, shape_value
Facebooktwittergoogle_plusredditpinterestlinkedinmailby feather

5 thoughts on “Building a better BeanProcessor

  1. Pingback: A Few More Words » JDBC ResultSet Mapper

  2. Karim

    Ive been working on a framework built on DbUtils, which sole intention is to simplify database work to a single object that can be used simply in many threads. The one feature I really would like to add is the “aggregate” concept you referred to in your bean mapper. Do you have a working version of this, and could I use it in my project (of course you will be given full credit). The project is being released under the apache 2 lic.

    Thanks in advance for your consideration,

    • Karim
    Reply
  3. warren Post author

    @Karim: Have a look at resultsetmapper. It is the open source implementation of the discussed problem.

    It can map resultset data to java beans (and their ‘aggregate’ components) in 2 ways:

    1. via annotations in the java bean
    2. via naming conventions and slight configuration (ie a list of the aggregate classes).

    Please let me know if it is of use, or if you would like me to improve in some way.

    Reply
  4. venu bothsa

    I have been working on JDBC using ResultSetMapper class. Here i am using Self join query. So mapping is not working if i bind duplicate columns to fields. Can you tell me solution.

    Thanks in advance.

    ResultSetMapper resultSetMapper = new ReflectionResultSetMapper(
    EndUserBean.class);
    return resultSetMapper.mapRow(userResultSet);

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *