Spring JDBC + Postgres SQL + Java 8 - conversion de/vers LocalDate
J'utilise Postgres SQL 9.2, Spring JDBC avec la version 4.0.5, et Java 8.
Java 8 introduit de nouvelles date/heure API et je voudrais l'utiliser, mais j'ai rencontré quelques difficultés.
J'ai créé une table TABLE_A:
CREATE TABLE "TABLE_A"
(
new_date date,
old_date date
)
Je suis à l'aide de Spring JDBC pour communiquer avec la base de données. J'ai créé classe Java qui correspond à ce tableau:
public class TableA
{
private LocalDate newDate;
private Date oldDate;
//getters and setters
}
c'est mon code qui est responsable de l'insertion de nouveaux ligne:
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);
}
Quand j'ai exécuté cette méthode, je suis d'exception:
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.
j'ai donc mis à jour cretion de BeanPropertySqlParameterSource:
BeanPropertySqlParameterSource parameterSource = new BeanPropertySqlParameterSource(tableA);
parameterSource.registerSqlType("newDate", Types.DATE);
après cette modification, j'ai pu insérer une ligne. Mais la prochaine, je voudrais extraire les lignes de la base de données. Voici ma méthode:
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);
}
et bien sûr, je suis d'exception:
...
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.
J'ai donc mis à jour mon code, cette fois BeanPropertyRowMapper, j'ai ajouté le service de conversion de haricot wrapper, qui est capable d'effectuer la conversion de java.sql.Date de java.temps.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);
et maintenant, tout fonctionne, mais c'est assez compliqué.
Est-il plus facile moyen de le réaliser?
Généralement parlant, je tiens à fonctionner sur LocalDate dans mon code Java, car il est beaucoup plus pratique, et être en mesure de persister dans la base de données. Je m'attends à ce qu'il devrait être activé par défaut.
OriginalL'auteur Adam Szecowka | 2014-08-27
Vous devez vous connecter pour publier un commentaire.
Nouvelle Date & Date de prise en charge des API avec JDBC est défini par JEP 170: JDBC 4.2. Postgres page de téléchargement compatibilité avec JDBC 4.2 les nouvelles fonctionnalités ne commence qu'à partir de la Postgres version 9.4, de sorte que certains problèmes de compatibilité pop up en utilisant la nouvelle API avec les conducteurs plus âgés.
Même
setObject(1, new java.util.Date());
est rejetée par la même contrainte dans Postgres (qui est acceptée avec joie par MySQL), pas seulement la nouvelle API commeLocalDate
. Certains comportements seront dépendant de l'implémentation, de sorte que seulejava.sql.*
est garanti assez bien (grosso modo).Comme pour le Printemps JDBC cadre, je pense que substituant son comportement travaille pour obtenir autour d'elle sans regretter plus tard. Je suggère une approche légèrement différente de ce que vous avez déjà fait:
BeanPropertySqlParameterSource
comportement de travailler avec la nouvelle date & le temps de l'API, et d'autres classes associées aux paramètres d'entrée si nécessaire (je ne suis pas familier avec ce Printemps de l'API).BeanPropertyRowMapper
à une autre classe pour aller chercher des opérations.De cette façon, vous améliorer refactoring capacités de l'API obtient prises en charge et de réduire la quantité de code nécessaire au cours du développement.
Vous pouvez aussi regarder quelques DAO approches.
je vous remercie pour votre commentaire. Cela fait l'affaire de trop pour moi
OriginalL'auteur BonanzaOne
Veuillez noter Java 8 Date et l'Heure de l'API (JSR 310) pris en charge, mais la mise en œuvre n'est pas complète: https://jdbc.postgresql.org/documentation/head/8-date-time.html citation:
Désolé, c'est de mal en effet
OriginalL'auteur Hubbitus