2011-10-11 9 views
10

Mi objeto de dominio tiene un par de campos de Joda-Time DateTime. Cuando estoy leyendo los valores de base de datos utilizando SimpleJdbcTemplate:Anulando BeanPropertyRowMapper para admitir JodaTime DateTime

paciente Paciente = jdbc.queryForObject (sql, nuevo BeanPropertyRowMapper (Patient.class), PatientID);

Simplemente falla y, sorprendentemente, no se registraron errores. Supongo que es porque el análisis timestamp a DateTime no funciona con Jdbc.

Si es posible heredar y anular BeanPropertyRowMapper y dar instrucciones para convertir todo java.sql.Timestamp y java.sql.Date a DateTime, sería grande y podría ahorrar una gran cantidad de código extra.

Algún consejo?

Respuesta

21

Lo que se debe hacer es subclase BeanPropertyRowMapper, anular initBeanWrapper(BeanWrapper) y registrar un editor de propiedades personalizado:

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<T> 
        extends BeanPropertyRowMapper<T> { 
    @Override 
    protected void initBeanWrapper(BeanWrapper bw) { 
     bw.registerCustomEditor(DateTime.class, new JodaDateTimeEditor()); 
    } 
} 
+0

Esto es exactamente lo que estoy buscando. Sin embargo, en realidad no está funcionando para mí. La ejecución se detiene en el momento en que ocurre un mapeo DateTime, sin embargo, no hay errores registrados: 'DEBUG: com.keype.hawk.system.jdbc.support.HawkBeanPropertyRowMapper [mapRow]: columna de mapeo 'date_added' a la propiedad 'fechaAdded' de tipo clase org. joda.time.DateTime' –

+0

Finalmente se dirigió al área problemática. setValue() se llama con un objeto TimeStamp como parámetro, pero en realidad es un JodaTime Per my logger: 'Un objeto compatible 2011-10-12 00: 00: 00.0. Tipo de objeto: java.sql.Timestamp. Fecha prevista ' –

+0

@firdousamir bien, he cambiado el código ahora. Prueba esta versión. –

2

En cuanto a BeanPropertyRowMapper aplicación, la forma de establecer los campos es:

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); 
} 

donde getColumnValue(rs, index, pd); delegados a JdbcUtils.getResultSetValue

Eso pd campo en getColumnValue es el verdadero "p ROPIEDAD d escriptor ", que se utiliza (pd.getPropertyType()) en JdbcUtils como tipo del campo para mapear.

Si nos fijamos en JdbcUtils código para getResultSetValue método, verá que simplemente va de un if comunicado a otro, para que coincida con pd.getPropertyType() a todos los tipos estándar. Cuando no encuentra uno, ya DateTime no es un tipo "estándar", se basa en un rs.getObject():

} else { 
// Some unknown type desired -> rely on getObject. 

Entonces, si este objeto es una Fecha de SQL se convierte en una Timestamp, y vuelve a ser establecido a un campo DateTime de su dominio => donde falla.

Por lo tanto, no parece ser una manera directa para inyectar un convertidor Date/Timestamp a DateTime en un BeanPropertyRowMapper. Por lo tanto, sería más limpio (y más eficiente) implementar su propio RowMapper.

En caso de que desee ver el error de asignación en una consola, configure su nivel de registro para org.springframework.jdbc para "depurar" o mejor aún para "rastrear" para ver exactamente qué sucede.

Una cosa que usted puede intentar, que no he probado, es extender una BeanPropertyRowMapper y sustituir una propiedad de DateTime escriba:

/** 
* Initialize the given BeanWrapper to be used for row mapping. 
* To be called for each row. 
* <p>The default implementation is empty. Can be overridden in subclasses. 
* @param bw the BeanWrapper to initialize 
*/ 
protected void initBeanWrapper(BeanWrapper bw) {} 
+0

Gracias tolitius. Eso fue lo que hice. No pude encontrar la forma tampoco. Es una cuestión de fila personalizada. –

1

La respuesta de @Sean Patrick Floyd es perfecta hasta que no haya muchos tipos personalizados.

Aquí un generalizado, configurable basado en la extensión de uso:

public class CustomFieldTypeSupportBeanPropertyRowMapper<T> extends BeanPropertyRowMapper<T> { 
    private Map<Class<?>, Handler> customTypeMappers = new HashMap<Class<?>, Handler>(); 

    public CustomFieldTypeSupportBeanPropertyRowMapper() { 
    super(); 
    } 

    public CustomFieldTypeSupportBeanPropertyRowMapper(Class<T> mappedClass, boolean checkFullyPopulated) { 
    super(mappedClass, checkFullyPopulated); 
    } 

    public CustomFieldTypeSupportBeanPropertyRowMapper(Class<T> mappedClass) { 
    super(mappedClass); 
    } 

    public CustomFieldTypeSupportBeanPropertyRowMapper(Class<T> mappedClass, Map<Class<?>, 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; 
    } 
}