Aller au contenu principal

Qualité de code — Checkstyle et SpotBugs

Un code qui compile et fonctionne n'est pas forcément un bon code. Des outils d'analyse statique permettent de détecter automatiquement les problèmes de style, les bugs potentiels et les mauvaises pratiques sans exécuter le programme.

Notions théoriques

Pourquoi l'analyse statique ?

Relire le code manuellement est lent et subjectif. Les outils d'analyse statique :

  • appliquent les conventions de façon objective et systématique
  • détectent des bugs que les tests ne couvrent pas encore
  • s'intègrent dans le build Maven pour bloquer le déploiement si des problèmes existent

Checkstyle — Respect des conventions

Checkstyle vérifie que votre code respecte un ensemble de règles de style. Il ne cherche pas de bugs, mais garantit la cohérence du code dans une équipe.

Configuration Maven

<!-- Dans pom.xml <plugins> -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<configLocation>checkstyle-google.xml</configLocation>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
</configuration>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals><goal>check</goal></goals>
</execution>
</executions>
</plugin>

Téléchargez checkstyle-google.xml depuis le dépôt GitHub de Checkstyle et placez-le à la racine de votre projet.

Règles Google Java Style vérifiées

CatégorieRègle
NommageClasses en PascalCase, variables et méthodes en camelCase
NommageConstantes en UPPER_SNAKE_CASE
FormatLongueur de ligne ≤ 100 caractères
ImportsPas d'imports * (import java.util.* interdit)
StructureUne seule instruction par ligne
JavadocJavadoc obligatoire sur les méthodes publiques

Lancer Checkstyle

mvn checkstyle:check # vérifier uniquement
mvn checkstyle:checkstyle # générer le rapport HTML
attention

mvn checkstyle:check fait échouer le build si des violations sont trouvées (comportement configuré avec failsOnError: true). C'est voulu : aucun code non conforme ne doit pouvoir être livré.

Exemples de violations courantes

// VIOLATION : nom de variable en PascalCase (devrait être camelCase)
String NomPersonnage = "Aragorn";

// VIOLATION : import wildcard
import java.util.*;

// VIOLATION : ligne trop longue
public Personnage creerPersonnageAvecTousLesParametres(String nom, int force, int defense, int mana) {

// CORRECTION
public Personnage creerPersonnage(
String nom, int force, int defense, int mana) {

Désactiver une règle ponctuellement

// CHECKSTYLE:OFF
// Code généré automatiquement — règle désactivée ici
private static final long serialVersionUID = -7043994889789898773L;
// CHECKSTYLE:ON
info

N'utilisez // CHECKSTYLE:OFF qu'en dernier recours pour du code généré automatiquement ou des contraintes externes. Ne jamais l'utiliser pour contourner une règle applicable.


SpotBugs — Détecter les bugs potentiels

SpotBugs (successeur de FindBugs) analyse le bytecode Java compilé à la recherche de patterns de bugs connus.

Configuration Maven

<!-- Dans pom.xml <plugins> -->
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.4.0</version>
<executions>
<execution>
<phase>verify</phase>
<goals><goal>check</goal></goals>
</execution>
</executions>
</plugin>

Catégories de bugs détectés

CatégorieExemple
Null derefAppel de méthode sur une valeur potentiellement null
Equals sans hashCodeequals() redéfini mais pas hashCode()
Ressource non ferméeConnection ou InputStream jamais fermé
SynchronisationVariable partagée sans synchronisation
Mauvaise comparaison== sur des objets String au lieu de .equals()
// BUG SpotBugs : comparaison d'objets avec ==
String nom = getNom();
if (nom == "Aragorn") { // FAUX : compare les références, pas les valeurs
System.out.println("Trouvé");
}

// CORRECTION
if ("Aragorn".equals(nom)) { // correct
System.out.println("Trouvé");
}
// BUG SpotBugs : equals() sans hashCode()
public class Personnage {
@Override
public boolean equals(Object o) { ... }
// MANQUE : hashCode() non défini → bug si utilisé dans une HashMap
}

Lancer SpotBugs

mvn spotbugs:check # vérifier (échoue si bugs trouvés)
mvn spotbugs:spotbugs # générer le rapport
mvn spotbugs:gui # ouvrir l'interface graphique

Le rapport HTML est généré dans target/site/.

Supprimer un faux positif

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

@SuppressFBWarnings(
value = "EQ_DOESNT_OVERRIDE_EQUALS",
justification = "hashCode non nécessaire car non utilisé dans collections"
)
public class Personnage { ... }
attention

Ne supprimez une alerte SpotBugs qu'après avoir compris pourquoi elle est levée et vérifié qu'elle est bien un faux positif. Les vraies alertes signalent de vrais bugs.

Exemple pratique

// Code avec problèmes — avant correction

public class personnageService { // CHECKSTYLE : classe en minuscule (devrait être PascalCase)

private List personnages; // SPOTBUGS : type raw sans générique

public Personnage TrouverParNom(String nom) { // CHECKSTYLE : méthode en PascalCase
for (int i = 0; i < personnages.size(); i++) {
Personnage p = (Personnage) personnages.get(i); // cast dangereux (raw type)
if (p.getNom() == nom) { // SPOTBUGS : == sur String
return p;
}
}
return null; // SPOTBUGS : risque NullPointerException à l'appelant
}
}

// Code corrigé — après Checkstyle + SpotBugs

public class PersonnageService {

private List<Personnage> personnages = new ArrayList<>();

public Optional<Personnage> trouverParNom(String nom) {
return personnages.stream()
.filter(p -> nom.equals(p.getNom()))
.findFirst();
}
}

Test de mémorisation/compréhension


Que vérifie Checkstyle dans votre code ?


Comment doit s'écrire le nom d'une classe en Java selon Google Style ?


Quelle commande Maven lance la vérification Checkstyle ?


Quel bug courant SpotBugs détecte-t-il quand on compare des String avec == ?


Que se passe-t-il si equals() est redéfini sans hashCode() dans une classe ?


Quelle annotation permet de supprimer un avertissement SpotBugs ?


TP pour réfléchir et résoudre des problèmes

Vous allez configurer Checkstyle et SpotBugs dans le projet RPG, puis corriger les problèmes détectés.

Étape 1 — Configurer Checkstyle dans pom.xml

Ajoutez le plugin maven-checkstyle-plugin avec la configuration Google Style.


Bonne pratique - Intégrer Checkstyle dans la phase validate

En liant Checkstyle à la phase validate (la première phase Maven), le build échoue immédiatement si le code n'est pas conforme. Cela empêche de continuer à compiler, tester et packager du code non conforme, économisant du temps en CI/CD.

Étape 2 — Identifier et corriger une violation Checkstyle

Voici du code avec des violations. Corrigez le nom de la méthode.

// Code actuel avec violations
public class PersonnageService {
public Personnage TrouverParNom(String nom) { // violation : PascalCase
// ...
}
}

Bonne pratique - camelCase pour méthodes et variables, PascalCase pour classes

En Java : classes → PascalCase (PersonnageService), méthodes et variables → camelCase (trouverParNom), constantes → UPPER_SNAKE_CASE (MAX_FORCE). Cette convention est universelle et rend le code immédiatement lisible par tout développeur Java.

Étape 3 — Corriger un bug détecté par SpotBugs

SpotBugs a signalé l'alerte ES_COMPARING_STRINGS_WITH_EQ dans ce code. Corrigez-le.


Bonne pratique - Toujours utiliser equals() pour les objets

L'opérateur == compare les références (les adresses mémoire) et non les valeurs. Deux String "Aragorn" créées séparément peuvent avoir des références différentes mais des valeurs identiques. Utilisez toujours .equals() pour les objets, jamais ==.

📌 Une solution