Using Spring 3.0.x, I wrote a SimpleJdbcCall defining with returningResultSet() a BeanPropertyRowMapper.
Now I want to replace the java.lang.Long type used for object IDs with a strongly typed ID, that is defining a PersonId class that holds the actual ID values as a Long variable.
I wrote a org.springframework.core.convert.converter.GenericConverter implementation that converts from the BigDecimal that is returned by JDBC to PersonID (and some others, for other classes).
I registered my converter as:
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="xxx.impl.IDTypeConverter"/>
</set>
</property>
The problem
Spring does not use my converter.
Debugging leads to method org.springframework.beans.TypeConverterDelegate.convertIfNecessary(String, Object, Object, Class, TypeDescriptor) where:
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
this method returns null. There are no conversions used.
Searching the web I found https://stackoverflow.com/a/12798635 where is says:
spring was trying to find a custom converter registered with PropertyEditor
Then it proposes a solution using a property editor but does not go into detail how to actually do it. (I asked there)
Another answer https://stackoverflow.com/a/53120800 says to use the method jdbcCustomConversions() from (Abstract)JdbcConfiguration, but I can't find those classes in my project.
I could write a custom RowMapper for each JDBC call, but that is a lot of code.
The question is: how to convert those datatypes with as few code as possible?
I came up with this solution in my DAO class, where the SimpleJdbcCall objects are used:
@Autowired
private ConversionService conversionService;
//...
{
BeanPropertyRowMapper<MyDTO> rowMapper1 = new BeanPropertyRowMapper<MyDTO>() {
@Override
protected void initBeanWrapper(BeanWrapper bw)
{
bw.setConversionService(conversionService);
}
};
rowMapper1.setMappedClass(MyDTO.class);
mySimpleJdbcCall.returningResultSet("p_my_object", rowMapper1);
This works (in JUnit tests) for reading data from database.
Writing
I used the solution from here: https://stackoverflow.com/a/50368110
Basically, override the getValue() method to specially handle my type:
BeanPropertySqlParameterSource parameterSource = new BeanPropertySqlParameterSource(pojo) {
@Override
public Object getValue(String paramName) throws IllegalArgumentException {
Object value = super.getValue(paramName);
if (value instanceof MyIDType) {
return ((MyIDType) value).getInternalValue();
}
return value;
}
};