Reputation: 981
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
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
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
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