Avec Spring JDBCTemplate, on peut récupérer des résultats d’une requête SQL sous forme d’une liste d’objets à la manière d’un ORM.
On peut notamment utiliser BeanPropertyRowMapper, une implémentation de RowMapper fournie par Spring permettant de mapper automatiquement les lignes retournées vers nos entités.
On va voir dans cet article quelques exemples d’utilisation sur des cas concrets 🙂
I. BeanPropertyRowMapper
Ce mapper est très pratique à utiliser car il permet de récupérer une liste d’objets simples sans aucune configuration. On va voir dans cette section comment il marche et ses limites:
Voici une entité très basique qui a 2 attributs: “id” et “name”:
public class KataEntity {
private Long id;
private String name;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Ma BDD a la configuration suivante:
CREATE TABLE KATA
(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
Pour récupérer une liste de Kata, on peut utiliser la méthode query() de JDBCTemplate qui prend en paramètre une requête SQL et un RowMapper.
@Override
public Collection<KataEntity> findAll() {
return jdbcTemplate.query("SELECT id, name FROM kata", new BeanPropertyRowMapper<>(KataEntity.class));
}
On remarque que BeanPropertyRowMapper prend en paramètre la classe vers laquelle transformer les résultats.
Pour effectuer le mapping, il va prendre les résultats de la requête et appeler les setters correspondants.
Si on décortique l’exemple, je vais avoir un résultat de la forme:
ID
NAME
1
AperoTech
Le mapper va déterminer les setters à utiliser suivant le nom des colonnes
id -> setId
name ->setName
Une fois fait, il va appeler le constructeur par défaut de la classe passée en paramètre (KataEntity dans mon cas) puis appeler les setters avec les données retournées.
En résumé, il fait donc
KataEntity kata = new KataEntity();
kata.setId(1)
kata.setName("AperoTech")
Pour l’utiliser, il faut donc:
– Une classe qui a un constructeur par défaut.
– Une classe avec des setters qui s’appellent comme les en-têtes des résultats.
C’est pour cette raison que ce mapper est pratique mais pas performant (comme il fait de l’introspection).
Que faire si mes setters ne matchent pas le nom des colonnes ?
On peut utiliser des alias, si j’ai:
CREATE TABLE KATA
(
id INT AUTO_INCREMENT PRIMARY KEY,
label VARCHAR(255) NOT NULL
);
et la même entité que précédemment, alors je peux faire:
@Override
public Collection<KataEntity> findAll() {
return jdbcTemplate.query("SELECT id, label as name FROM kata", new BeanPropertyRowMapper<>(KataEntity.class));
}
Si j’ai un objet qui a pour attributs d’autres objets ?
Spring JDBCTemplate est une surcouche au JDBC mais pas un ORM, vous ne pourrez pas faire ce mapping simplement. J’ai pu croiser plusieurs magouilles pour arriver à cette fin mais je vous conseille la façon standard: créer un rowMapper dédié et ne pas utiliser BeanPropertyRowMapper.
II. Utiliser un RowMapper personnalisé
Imaginons que mon objet Kata défini précédemment ait en attribut un objet quelconque. Dans ma table, j’ai une colonne “objectId” avec l’id d’un objet. On devrait alors faire un Mapper:
public class KataEntityRowMapper implements RowMapper<KataEntity> {
@Override
public KataEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
KataEntity entity = new KataEntity();
entity.setId(rs.getLong("id"));
entity.setName(rs.getString("name"));
entity.customMethod(rs.getString("objectId"));
return entity;
}
}
Puis l’appeler via
@Override
public Collection<KataEntity> findAll() {
return jdbcTemplate.query("SELECT id, label as name FROM kata", new KataEntityRowMapper());
}
Conclusion
Vous avez à présent toutes les cartes en main pour récupérer les résultats de vos requêtes dans des objets avec Spring JDBCTemplate 🙂 Le code des mappers peut paraître boilerplate (et à mon sens il l’est) mais il ne faut pas oublier qu’on utilise une surcouche à l’API JDBC et pas un ORM !
Introduction
Sur un des projets sur lesquels j’interviens, diverses personnes ont contribué au cours des années parfois sans passation entre les équipes.
En regardant les commits, on voit qu’une équipe a mis un ORM, une autre l’a enlevé, une autre a mis un autre ORM etc..
Le coût en temps pour l’entreprise est considérable car ce n’est pas une opération a...
Introduction
Vous avez diagnostiqué une fuite mémoire et vous voulez corriger le problème.
Si vous utilisez IntelliJ, vous avez à disposition dans votre IDE un outil puissant qui vous permettra de diagnostiquer la source du problème et vérifier vot...
Introduction
JaCoCo est un outil très connu dans le monde Java qui permet de générer des rapports de code coverage au format xml et html.
L’intérêt sera souvent de donner le rapport au format xml à d’autres outils (Codecov ou Sonar par exemp...
Introduction
Dans nos applications, il y a souvent des objets qui dépendent les uns des autres (un Service avec des Repository par exemple). Si on devait satisfaire ces dépendances “à la main”, on devrait les instancier, vérifier que ça n’ait pas ...