Question

I wanted to know what the community considers the "best practices" in respect to mapping class hierarchies with Spring JDBC.

We do not have the ability to use a full fledged ORM tool, however we are using the Spring JDBC to alleviate some of the tedious nature of JDBC. One class which we leverage very regularly are the BeanPropertyRowMapper for it's ease of use and the ability to have type insensitive bean property access from our result set.

I have a class hierarchy that all maps back to a single table (taking the table-per-hiearchy approach for this small class hierarchy). As such, the table contains an classId column which can be used to determine what class should actually be instantiated. Ex. 1 = Manager, 2 = Employee, 3 = Contractor. All of these are "People" but each subclass of person has a few attributes which are unique to their class.

My initial thought is to create a subclass of BeanPropertyRowMapper and try and inject this logic to say "if column A = 1 then instantiate a Manager and then do your nomral binding".

Does this seem like a reasonable approach? Are there any other suggestions people may have that have worked for you?

Thanks in advance for your replies,

Justin N.

Was it helpful?

Solution

It doesn't look like there's a place in the subclass where you could add a hook to switch the class without completely copying the implementation of mapRow() for BeanPropertyRowMapper. Your best approach might be to create a RowMapper class that delegates to the appropriate BeanPropertyRowMapper.

For example:

    final RowMapper managerMapper = new BeanPropertyRowMapper(Manager.class);
    final RowMapper employeeMapper = new BeanPropertyRowMapper(Employee.class);
    final RowMapper contractorMapper = new BeanPropertyRowMapper(Contractor.class);

    RowMapper rm = new RowMapper()
    {
        @Override
        public Object mapRow(ResultSet rs, int rowNum)
            throws SQLException
        {
            int employeeType = rs.getInt("type");
            switch (employeeType)
            {
                case 1:
                    return managerMapper.mapRow(rs, rowNum); 

                case 2:
                    return employeeMapper.mapRow(rs, rowNum);

                case 3:
                    return contractorMapper.mapRow(rs, rowNum);

                default:
                    break;

            }
        }
    };

OTHER TIPS

I'm not sure it's the 'best practice' but i suggest the following approach (without using bean properties --> should work faster).

Usually you know what kind of object you expect to retrieve. So you can provide corresponding row mapper when execute the sql.

Declare custom abstract generic RowMapper and create own row mapper for each type of person, i.e.:

private static abstract class PersonRowMapper<T extends Person> implements RowMapper<T> {

 @Override
 public abstract T mapRow(ResultSet rs, int rowNum) throws SQLException;

 protected void mapBase(ResultSet rs, T person) throws SQLException {
  //base mapping here
 }
}


private static class EmployeeRowMapper extends PersonRowMapper<Employee> {

 @Override
 public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
  Employee e = new Employee();
  mapBase(rs, e);
  //set other specific employee props
 }
}

By other approach you can declare abstract method in base mapper for specific props, i.e.

private static abstract class PersonRowMapper<T extends Person> implements RowMapper<T> {
 @Override
 public T mapRow(ResultSet rs, int rowNum) throws SQLException {
  T instance = getInstance();
  //set base props here
  fill(rs, instance);
 }

 //e.g. return new Employee()
 protected abstract T getInstance();
 //fill specific instance props
 protected abstract void fill(ResultSet rs, T instance) throws SQLException;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top