2011-10-11 17 views
10

L'oggetto Mio dominio contiene un paio di campi Joda-Time DateTime. Quando sto leggendo i valori di database utilizzando SimpleJdbcTemplate:Overriding BeanPropertyRowMapper per il supporto di JodaTime DateTime

paziente Patient = jdbc.queryForObject (SQL, nuova BeanPropertyRowMapper (Patient.class), PatientID);

Non funziona e, sorprendentemente, non sono stati registrati errori. Suppongo che sia a causa dell'analisi timestamp a DateTime non funziona con Jdbc.

Se è possibile ereditare e sovrascrivere BeanPropertyRowMapper e istruire per convertire tutti java.sql.Timestamp e java.sql.Date-DateTime, sarebbe bello e potrebbe risparmiare un sacco di codice aggiuntivo.

Qualche consiglio?

risposta

21

La cosa giusta da fare è quello di creare una sottoclasse BeanPropertyRowMapper, ignorare initBeanWrapper(BeanWrapper) e registra un Editor di proprietà personalizzato:

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

Questo è esattamente quello che sto cercando. Tuttavia, non funziona davvero per me. L'esecuzione si interrompe nel momento in cui si verifica un mapping DateTime, tuttavia non vengono registrati errori: 'DEBUG: com.keype.hawk.system.jdbc.support.HawkBeanPropertyRowMapper [mapRow]: Mappatura della colonna 'date_added' alla proprietà 'dateAdded' di tipo class org. joda.time.DateTime' –

+0

Finalmente riuscito all'area problematica. setValue() viene chiamato con un oggetto TimeStamp come parametro, ma in realtà è un JodaTime Per il mio logger: 'Un oggetto supportato 2011-10-12 00: 00: 00.0. Tipo di oggetto: java.sql.Timestamp. Expected DateTime' –

+0

@firdousamir ok, ho cambiato il codice ora. Prova questa versione. –

2

Guardando BeanPropertyRowMapper implementazione, il modo in cui definisce i campi è:

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

dove getColumnValue(rs, index, pd); delegati per JdbcUtils.getResultSetValue

Che pd campo nella getColumnValue è il vero e proprio "p ROPRIETÀ d escriptor ", che viene utilizzato (pd.getPropertyType()) in JdbcUtils come tipo del campo su cui mappare.

Se si guarda JdbcUtils codice per getResultSetValue metodo, vedrai che va semplicemente da una dichiarazione if ad un altro, per abbinare pd.getPropertyType() a tutti i tipi standard. Quando non trova uno, dal momento che DateTime non è un tipo di "standard", si basa su un rs.getObject():

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

Allora, se questo oggetto è un Data SQL si converte in un Timestamp, e restituisce da impostare a un campo DateTime del tuo dominio => dove non riesce.

Quindi, non sembra essere un modo dritto in avanti per iniettare un convertitore Date/Timestamp a DateTime in un BeanPropertyRowMapper. Quindi sarebbe più pulito (e più performante) implementare il tuo RowMapper.

Nel caso in cui si desideri visualizzare l'errore di associazione in una console, impostare il livello di registrazione per org.springframework.jdbc su "debug" o meglio ancora "traccia" per vedere esattamente cosa succede.

Una cosa si può provare, che non ho ancora testato, è quello di estendere un BeanPropertyRowMapper e sovrascrivere una proprietà di DateTime digitare:

/** 
* 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

Grazie tolitius. Questo è quello che ho fatto. Nemmeno io riuscivo a capire. Una riga personalizzata è importante. –

1

La risposta di @Sean Patrick Floyd è perfetta finché non si dispone di molti molti tipi personalizzati.

Qui una generalizzata, configurabile in base all'estensione utilizzo:

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