Objectif : Lors de la mise à jour d'un objet, il est nécessaire de consigner les détails des changements, notamment le nom du champ, sa valeur avant modification et sa valeur après modification.
Aprpoche : Comparer deux instances d'un même bean pour identifier les écarts de valeurs. Afin de réutiliser cette logique pour différents types de beans, on exploite les génériques et la réflexion pour une implémentation générique.
Étapes d'implémentation
Définition d'une annotation personnalisée
package com.example.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MarquerChangement {
String libelle() default "";
}
Application de l'annotation aux champs du bean
package com.example.modele;
import com.example.annotation.MarquerChangement;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Employe {
private Long identifiant;
@MarquerChangement(libelle = "Nom complet")
private String nom;
@MarquerChangement(libelle = "Âge")
private Integer age;
}
Implémentation du détecteur de changements
package com.example.util;
import com.example.annotation.MarquerChangement;
import java.lang.reflect.Field;
import java.util.Objects;
public class DetecteurChangement {
public static <T> String extraireModifications(T objetMisAJour, T objetInitial) {
Field[] champs = objetMisAJour.getClass().getDeclaredFields();
StringBuilder resultat = new StringBuilder();
for (Field champ : champs) {
champ.setAccessible(true);
if (champ.isAnnotationPresent(MarquerChangement.class)) {
try {
Object nouvelleValeur = champ.get(objetMisAJour);
Object ancienneValeur = champ.get(objetInitial);
if (!Objects.equals(nouvelleValeur, ancienneValeur)) {
String libelle = champ.getAnnotation(MarquerChangement.class).libelle();
resultat.append(libelle)
.append(" : Anciennement = ")
.append(ancienneValeur)
.append(", Nouvellement = ")
.append(nouvelleValeur)
.append("\n");
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return resultat.toString();
}
}
Exemple de test
package com.example;
import com.example.modele.Employe;
import com.example.util.DetecteurChangement;
public class TestDetecteur {
public static void main(String[] args) {
Employe avant = Employe.builder()
.identifiant(101L)
.nom("Alice Martin")
.age(30)
.build();
Employe apres = Employe.builder()
.identifiant(101L)
.nom("Alice Dupont")
.age(31)
.build();
String changements = DetecteurChangement.extraireModifications(apres, avant);
System.out.println(changements);
// Sortie attendue :
// Nom complet : Anciennement = Alice Martin, Nouvellement = Alice Dupont
// Âge : Anciennement = 30, Nouvellement = 31
}
}