2014-08-27 16 views
7

Sto usando Postgres SQL 9.2, Spring JDBC con versione 4.0.5 e Java 8.
Java 8 ha introdotto una nuova API data/ora e vorrei per usarlo, ma ho incontrato alcune difficoltà. ho creato tabella TABLE_A:Spring JDBC + Postgres SQL + Java 8 - conversione da/a LocalDate

CREATE TABLE "TABLE_A" 
(
    new_date date, 
    old_date date 
) 

Sto usando Spring JDBC per comunicare con il database. Ho creato classe Java, che corrisponde a questa tabella:

public class TableA 
{ 
    private LocalDate newDate; 
    private Date oldDate; 
    //getters and setters 

} 

questo è il mio codice, che è reponsible per l'inserimento di nuova riga:

public void create(TableA tableA) 
{ 
    BeanPropertySqlParameterSource parameterSource = new BeanPropertySqlParameterSource(tableA); 
    final String sql = "INSERT INTO public.TABLE_A (new_date,old_date) values(:newDate,:oldDate)"; 
    namedJdbcTemplate.update(sql,parameterSource); 

} 

Quando ho eseguito questo metodo ho ottenuto un'eccezione:

org.postgresql.util.PSQLException: Can't infer the SQL type to use for an instance of java.time.LocalDate. Use setObject() with an explicit Types value to specify the type to use. 

cretion così ho aggiornato dei BeanPropertySqlParameterSource:

BeanPropertySqlParameterSource parameterSource = new BeanPropertySqlParameterSource(tableA); 
parameterSource.registerSqlType("newDate", Types.DATE); 

dopo quella modifica, ero in grado di inserire una riga. Ma dopo, vorrei recuperare le righe dal database. Qui è il mio metodo:

public List<TableA> getAll() 
{ 
    final String sql = "select * from public.TABLE_A"; 
    final BeanPropertyRowMapper<TableA> rowMapper = new BeanPropertyRowMapper<TableA>(TableA.class); 
    return namedJdbcTemplate.query(sql,rowMapper); 
} 

e, naturalmente, ho ottenuto eccezione:

... 
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:474) 
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:511) 
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1119) 
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:902) 
at org.springframework.jdbc.core.BeanPropertyRowMapper.mapRow(BeanPropertyRowMapper.java:255) 
... 
Caused by: java.lang.IllegalStateException: Cannot convert value of type [java.sql.Date] to required type [java.time.LocalDate] for property 'newDate': no matching editors or conversion strategy found. 

Così ho aggiornato il mio codice, questa volta BeanPropertyRowMapper, ho aggiunto servizio di conversione di involucro di fagioli, che è in grado di eseguire conversione da java.sql.Date a java.time.LocalDate

public List<TableA> getAll() 
{ 
    final String sql = "select * from public.TABLE_A"; 
    final BeanPropertyRowMapper<TableA> rowMapper = new BeanPropertyRowMapper<TableA>(TableA.class) 
    { 
     @Override 
     protected void initBeanWrapper(BeanWrapper bw) { 
      super.initBeanWrapper(bw); 
      bw.setConversionService(new ConversionService() { 
       @Override 
       public boolean canConvert(Class<?> aClass, Class<?> aClass2) { 
        return aClass == java.sql.Date.class && aClass2 == LocalDate.class; 
       } 

       @Override 
       public boolean canConvert(TypeDescriptor typeDescriptor, TypeDescriptor typeDescriptor2) { 
        return canConvert(typeDescriptor.getType(), typeDescriptor2.getType()); 
       } 

       @Override 
       public <T> T convert(Object o, Class<T> tClass) { 
        if(o instanceof Date && tClass == LocalDate.class) 
        { 
         return (T)((Date)o).toLocalDate(); 
        } 

        return null; 


     } 

      @Override 
      public Object convert(Object o, TypeDescriptor typeDescriptor, TypeDescriptor typeDescriptor2) { 
       return convert(o,typeDescriptor2.getType()); 
      } 
     }); 
    } 
} ; 

return namedJdbcTemplate.query(sql,rowMapper); 

e ora tutto funziona, ma è piuttosto complicato.
È più semplice ottenere questo? In generale, Mi piacerebbe operare su LocalDate nel mio codice Java, perché è molto più conveniente, ed essere in grado di persistere nel database. Mi aspetterei che dovrebbe essere abilitato di default.

risposta

6

Nuova data & Il supporto dell'API data con JDBC è definito da JEP 170: JDBC 4.2. La compatibilità di Postgres download page con JDBC 4.2 inizia solo a partire dalla versione 9.4 di Postgres, quindi alcune sfide di compatibilità appariranno utilizzando la nuova API con driver più vecchi.

Anche setObject(1, new java.util.Date()); viene rifiutato dallo stesso vincolo in Postgres (che è felicemente accettato da MySQL), non solo la nuova API come LocalDate. Alcuni comportamenti dipenderanno dall'implementazione, quindi solo lo java.sql.* è praticamente garantito (in parole povere).


Per quanto riguarda il framework Spring JDBC, credo ignorando il suo comportamento lavora per aggirare l'ostacolo senza rimpiangere un secondo momento. Suggerisco un approccio leggermente diverso per quello che hai già fatto:

  1. Estendere BeanPropertySqlParameterSource comportamento di lavorare con la nuova data & time API, e le altre classi associate con l'input dei parametri, se necessario (non ho familiarità con tale API Spring) .
  2. Estrarre il comportamento già annullato di BeanPropertyRowMapper in un'altra classe per il recupero delle operazioni.
  3. Avvolgi tutto con un modello di fabbrica o una classe di utilità in modo da non doverlo più esaminare.

In questo modo si migliorano le funzionalità future di refactoring se l'API viene supportata e si riduce la quantità di codice necessaria durante lo sviluppo.

Si potrebbe anche guardare alcuni approcci DAO.

+1

Ho corretto il mio * org.postgresql.util.PSQLException: non è possibile inferire il tipo SQL da utilizzare per un'istanza di java.time.LocalDate. Utilizzare setObject() con un valore Tipi esplicito per specificare il tipo da utilizzare * aggiornamento dell'aggiornamento del mio JDBC postgres da * 9.4 Build 1206 * a * 9.4.1212 * versione –

+0

grazie per il tuo commento. Anche questo è per me il trucco – flipperweid

Problemi correlati