David Buckley
David Buckley

Reputation: 981

Spring - How to insert a nested bean using a SimpleJdbcDaoSupport class

I have two beans (POJOs) - a Customer and an address class defined like this:

public class Customer {
  private String name = null;
  private Address address = null;

  public Customer() {
    address = new Address();
  }

  public String getName() {
    return name;
  }

  public void setName(name) {
    this.name = name;
  }
  //additional setters/getters for various properties
}

public class Address {
  private String street = null;

  public String getStreet() {
    return street;
  }

  public void setStreet(street) {
    this.street = street;
  }
  //additional setters/getters for various properties
}

I'm trying to insert this to the database using like this:

public class CustomerDAO extends SimpleJdbcDaoSupport {
  public int addOrganization(Customer customer) {

    SimpleJdbcInsert insertCustomer = null;
    BeanPropertySqlParameterSource params = null;
    Number customerID = null;

    insertTransaction = new SimpleJdbcInsert(getDataSource()).withTableName("customers")
            .usingGeneratedKeyColumns("customerID");

    params = new BeanPropertySqlParameterSource(customer);

    customerID = insertTransaction.executeAndReturnKey(params);

    return customerID.intValue();
  }
}

The problem is I get an Invalid argument value: java.io.NotSerializableException and it doesn't insert the Customer. I can remove the address from the database and it will insert the other customer data. Or, I can do something like this:

MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("name", customer.getName());
params.addValue("street", customer.getAddress().getStreet());

but that eliminates the ease of the BeanPropertySqlParameterSource class and if I add or remove any properties, I have to add another line.

Is there an easy way to store the nested Address bean without having to manually add each value? How do I have to define the database and/or beans to make this happen?

Upvotes: 2

Views: 4189

Answers (3)

kfox
kfox

Reputation: 1186

There is a way to do this with MapSqlParameterSource and reflection. Some code below. (the disadvantage is that you have to use reflection, but advantage is that you don't have to worry about adding/removing fields).

You will need to have the Customer class and the Address class extend from AbstractBean or some other class.

public static MapSqlParameterSource generate(Customer bean) {
    try {
        MapSqlParameterSource source = new MapSqlParameterSource();
        addAllFields(bean, source, bean.getClass().getDeclaredFields());
        return source;
    } catch (IllegalAccessException e) {
        throw new IllegalStateException("Unable to generate the parameter source", e);
    }
}

private static void addAllFields(AbstractBean bean, MapSqlParameterSource source, Field[] fields)
    throws IllegalAccessException {
    for (Field field : fields) {
        field.setAccessible(true);
        if (field.getType().isAssignableFrom(Address.class)) {
            Address address = (Address)field.get(bean);
            addAllFields(address, source, address.getClass().getDeclaredFields());
        } else {
            source.addValue(field.getName(), field.get(bean));
        }
    }
}

Upvotes: 1

Espen
Espen

Reputation: 10745

Your solution is the simplest.

If you must insert data from nested objects and you don't like to add parameters to a map, then you should consider using JPA instead.

Upvotes: 2

Kartik
Kartik

Reputation: 2609

you can define inner beans. Take a look at section 3.3.2.3 on inner beans. This is the link http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-inner-beans

Upvotes: 0

Related Questions