|
Tutorial Annotation JDK 1.5: traitement au runtime
|  |
Dans cet exemple, les annotations vont être utilisées pour décrire des autorisations sur des méthodes Java, et pour permettre de tracer l'appel de certaines méthodes.
1- Déclarer l'annotation CerbèreInfo
L'annotation CerbèreInfo contient un tableau d'utilisateurs autorisés à utiliser cette méthode, et un booléen permettant de tracer à la demande tous les appels à cette méthode. Dans cet exemple, les trace sont juste affichées à l'écran pour simplifier le code.
|
package com.btc.tutorial.cerbère;
import java.lang.annotation.*;
// L'annotation peut être utilisée au moment de l'execution
@Retention(RetentionPolicy.RUNTIME)
// L'annotation peut être placée sur une méthode
@Target(ElementType.METHOD)
public @interface CerbèreInfo {
// Nom de l'utilisateur autorisé ou * pour tout le monde
String[] autorise() default {"*"};
// true: les accés à cette méthodes sont écrits dans un fichier d'audit
boolean audit() default false;
} |
| Fichier: CerbèreInfo.java |
2- Utiliser l'annotation CerberInfo sur une classe
Dans l'exemple suivant, nous créons une classe Java, en ajoutant l'annotation permettant de connaitre l'auteur du code:
package com.btc.tutorial.cerbère;
public class Entreprise {
private String nom;
// Tous le monde peut utiliser cette méthode, mais les accés sont enregistrés (audit)
@CerbèreInfo (
autorise={"*"},
audit=true
)
public String getNom() {
Cerbere.vérifier(this, "getNom");
return nom;
}
// Seul admin peut utiliser cette méthode, et les accés sont enregistrés (audit)
@CerbèreInfo (
autorise={"admin", "bob"},
audit=true
)
public void setNom(String nom) {
Cerbere.vérifier(this, "setNom", String.class);
this.nom = nom;
}
}
|
| Fichier: Company.java |
3- Accéder aux annotations
La classe Cerbère permet de vérifier si l'utilisateur a ou non le droit de déclencher une méthode.
L'utilisateur est stockée par la classe Cerbère dans une String (simplifié pour l'exemple).
Regardons le code source:
package com.btc.tutorial.cerbère;
import java.lang.reflect.*;
public class Cerbère {
// Le nom de l'utilisateur connecté (simplifié pour l'exemple)
private static String _utilisateur;
public static synchronized void setUtilisateur(String utilisateur) {
_utilisateur = utilisateur;
}
public static String getUtilisateur() {
return _utilisateur;
}
// Vérifier si l'utilisateur a le droit d'appeler cette méthode
// Cette méthode utilise une nouveauté du JDK 1.5, les varargs permettant de passer
// un nombre variable de paramètres.
public static void vérifier(Object object, String methodName, Class... paramTypes) {
try {
// Créer un tableau contenant les types des paramètres de la méthode
Class paramTypesArray[] = new Class[paramTypes.length];
// Remplir le tableau à partir des parmaètres de la méthode
int i = 0;
// Ca aussi c'est une nouveauté du JDK 1.5!
for (Class paramType : paramTypes)
paramTypesArray[i++] = paramType;
// Récupérer la méthode appelée.
Method method = object.getClass().getMethod(methodName, paramTypesArray);
// S'il n'y a pas d'annotation, autoriser l'appel
if( !method.isAnnotationPresent(CerbèreInfo.class) ) return;
// Récupérer l'annotation CerbèreInfo
CerbèreInfo info = method.getAnnotation(CerbèreInfo.class);
// Vérifier si l'utilisateur est autorisé à utiliser cette méthode
if( vérifier(info.autorise(), getUtilisateur()) ) {
// Si l'audit est activé pour cette méthode, ajouter l'appel de la méthode
if( info.audit() ) log("[Cerbère] INFO: User " + getUtilisateur() + " granted to call " + methodName);
return;
}
} catch (Exception e) {
// Il y a un problème quelque part
exception("[Cerbère] ERROR: while checking acces to " + methodName);
}
// L'utilisateur n'a pas le droit d'utiliser cette méthode
exception("[Cerbère] ALERT: access to " + methodName + " denied to " + getUtilisateur());
}
// Vérifier si l'utilisateur fait partie des utilisateurs autorisés
private static boolean vérifier(String[] autorisés, String utilisateur) {
// Une nouveauté bien sympathique du JDK 1.5
for(String autorisé: autorisés) {
// Si "*", alors tous les utilisateurs peuvent déclencher cette méthode
if( autorisé.equals("*") ) return true;
if( utilisateur.equals(autorisé) ) return true;
}
// L'utilisateur ne fait pas partie des utilisateurs autorisés
return false;
}
private static void exception(String msg) {
// Logger le problème
log(msg);
// Envoyer une exception (RuntimeException pour simplifier l'exemple)
throw new RuntimeException(msg);
}
private static void log(String msg) {
// Un peut minimaliste comme système d'audit, mais cela permet de simplifier l'exemple
System.err.println("[Cerbère] " + msg);
}
}
|
| Fichier: Cerbère.java |
Si vous connaissez AOP (Aspect Oriented Programming), vous pouvez imaginer la puissance de la solution AOP + Annotation: AOP vous permet de ne pas avoir à écrire Cerbère.vérifier(...) dans vore code, cet appel étant automatiquement ajouté par un outil AOP. Nous reviendrons sur ce sujet.
La page suivante vous présente l'annotation Todo et l'outil de traitement des annotations
|