重写BeanPropertyRowMapper以支持JodaTime DateTime
My Domain对象有几个Joda-Time DateTime
字段。 当我使用SimpleJdbcTemplate读取数据库值时:
患者患者= jdbc.queryForObject(sql,new BeanPropertyRowMapper(Patient.class),patientId);
它只是失败,令人惊讶的是,没有记录任何错误。 我想这是因为解析到DateTime
的timestamp
不适用于Jdbc。
如果可以inheritance和覆盖BeanPropertyRowMapper
并指示将所有java.sql.Timestamp
和java.sql.Date
转换为DateTime
,那么它会很棒并且可以节省大量额外代码。
任何建议?
正确的做法是initBeanWrapper(BeanWrapper)
BeanPropertyRowMapper
,重写initBeanWrapper(BeanWrapper)
并注册自定义属性编辑器:
public class JodaDateTimeEditor extends PropertyEditorSupport { @Override public void setAsText(final String text) throws IllegalArgumentException { setValue(new DateTime(text)); // date time in ISO8601 format // (yyyy-MM-ddTHH:mm:ss.SSSZZ) } @Override public void setValue(final Object value) { super.setValue(value == null || value instanceof DateTime ? value : new DateTime(value)); } @Override public DateTime getValue() { return (DateTime) super.getValue(); } @Override public String getAsText() { return getValue().toString(); // date time in ISO8601 format // (yyyy-MM-ddTHH:mm:ss.SSSZZ) } } public class JodaTimeSavvyBeanPropertyRowMapper extends BeanPropertyRowMapper { @Override protected void initBeanWrapper(BeanWrapper bw) { bw.registerCustomEditor(DateTime.class, new JodaDateTimeEditor()); } }
查看BeanPropertyRowMapper
实现,它设置字段的方式是:
Object value = getColumnValue( rs, index, pd ); if (logger.isDebugEnabled() && rowNumber == 0) { logger.debug("Mapping column '" + column + "' to property '" + pd.getName() + "' of type " + pd.getPropertyType()); } try { bw.setPropertyValue(pd.getName(), value); }
其中getColumnValue(rs, index, pd);
委托给JdbcUtils.getResultSetValue
getColumnValue
中的pd
字段是实际的“ p roperty d escriptor”,它在JdbcUtils
用作( pd.getPropertyType()
)作为要映射到的字段的类型 。
如果你看一下getResultSetValue
方法的JdbcUtils
代码,你会看到它只是从一个if
语句转到另一个,以匹配pd.getPropertyType()
到所有标准类型。 当它找不到时,由于DateTime
不是“标准”类型,它依赖于rs.getObject()
:
} else { // Some unknown type desired -> rely on getObject.
然后,如果此对象是SQL Date,则将其转换为Timestamp
,并返回以设置为domain =>的DateTime
字段。
因此,似乎没有一种向DateTime
转换器注入Date
/ Timestamp
到BeanPropertyRowMapper
。 因此,实现自己的RowMapper会更干净(也更高效)。
如果您希望在控制台中看到映射错误,请将org.springframework.jdbc
的日志记录级别设置为“debug”或更好地“跟踪”以确切了解发生的情况。
您可以尝试的一件事,我还没有测试,是扩展BeanPropertyRowMapper
并覆盖DateTime
类型的属性:
/** * Initialize the given BeanWrapper to be used for row mapping. * To be called for each row. * The default implementation is empty. Can be overridden in subclasses. * @param bw the BeanWrapper to initialize */ protected void initBeanWrapper(BeanWrapper bw) {}
@Sean Patrick Floyd的答案是完美的,直到你没有很多自定义类型。
这是一个基于使用扩展的通用可配置:
public class CustomFieldTypeSupportBeanPropertyRowMapper extends BeanPropertyRowMapper { private Map, Handler> customTypeMappers = new HashMap, Handler>(); public CustomFieldTypeSupportBeanPropertyRowMapper() { super(); } public CustomFieldTypeSupportBeanPropertyRowMapper(Class mappedClass, boolean checkFullyPopulated) { super(mappedClass, checkFullyPopulated); } public CustomFieldTypeSupportBeanPropertyRowMapper(Class mappedClass) { super(mappedClass); } public CustomFieldTypeSupportBeanPropertyRowMapper(Class mappedClass, Map, Handler> customTypeMappers) { super(mappedClass); this.customTypeMappers = customTypeMappers; } @Override protected Object getColumnValue(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException { final Class> current = pd.getPropertyType(); if (customTypeMappers.containsKey(current)) { return customTypeMappers.get(current).f(rs, index, pd); } return super.getColumnValue(rs, index, pd); } public void addTypeHandler(Class> class1, Handler handler2) { customTypeMappers.put(class1, handler2); } public static interface Handler { public Object f(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException; } }