EN · DE · RU · FR · ES

#800 : ExceptionHelper.java

projectforge-business/src/main/java/org/projectforge/framework/utils/ExceptionHelper.java · 97 lignes · 50 code · 39 commentaires · 8 vides
Trois méthodes utilitaires statiques pour la gestion des exceptions : traces de pile filtrées (réduction des trames non pertinentes et saut des proxies CGLIB), trace de pile en chaîne (printStackTrace standard vers un writer), et résolution récursive de la cause racine. Utilisées principalement par la couche de sécurité/accès pour produire des messages d'erreur lisibles qui n'affichent que les chemins de code ProjectForge, et non les internes de Spring/Hibernate/Tomcat.

Méthodes

MéthodeCe qu'elle faitPourquoi elle existe
getFilteredStackTrace(ex, namespace) Construit une chaîne de trace de pile contenant uniquement les trames du namespace donné. Les trames consécutives non correspondantes sont réduites en "at ...". Les trames contenant CGLIB$$ sont toujours ignorées — ce sont des classes proxy Hibernate avec des noms déformés comme AddressDO$$EnhancerByCGLIB$$a1b2c3d4. Les erreurs de violation d'accès afficheraient sinon 50+ lignes d'internes Spring Security et Tomcat avant d'afficher la seule ligne ProjectForge pertinente. La trace filtrée montre uniquement la chaîne d'appels pertinente pour le développeur.
printStackTrace(ex) Convertit une trace de pile complète en chaîne via StringWriter+PrintWriter. Pattern Java standard. Les frameworks de journalisation ont besoin d'une chaîne, pas d'un PrintStream. Utilisé lorsque les exceptions doivent être sérialisées en JSON ou stockées dans des colonnes de base de données.
getRootCause(ex) Déroule récursivement getCause() jusqu'à trouver l'exception la plus interne. Retourne l'exception originale si aucune cause n'existe. Spring encapsule fortement les exceptions (UndeclaredThrowableException, InvocationTargetException, DataAccessException). La véritable erreur se trouve toujours en bas. Cette méthode l'extrait.

Algorithme de filtrage par namespace

La méthode getFilteredStackTrace utilise une approche par machine d'états avec deux modes :

Mode normal : Impression des trames. Lorsqu'une trame non correspondante est rencontrée, elle affiche "at ..." (réduisant les trames non pertinentes) et passe en mode ignoré.
Mode ignoré : Ignorer les trames silencieusement jusqu'à ce qu'une trame correspondante apparaisse, puis revenir en mode normal et l'afficher.

Cela produit une sortie compacte comme : at org.projectforge.access.AccessChecker.check(AccessChecker.java:79) at ... at org.projectforge.task.TaskDao.hasAccess(TaskDao.java:176) — où "at ..." remplace toutes les trames Spring/Tomcat/Hibernate entre les deux lignes pertinentes.

Consommateurs

Appelée par la couche de contrôle d'accès (AccessCheckerImpl, AccessException) lors de la construction des messages d'erreur pour les violations de permissions. Également utilisée par ScriptExecutor pour produire une sortie d'erreur lisible pour les échecs de scripts Groovy/Kotlin — sans la trace filtrée, une simple NPE dans un script produirait une trace de pile de 200 lignes dominée par le runtime Groovy et les internes des proxies Spring.

Historique Git

CommitCe qui a changé
868d6abb7Copyright 2025→2026
63081666fCopyright 2024→2025
b6092df09Copyright 2023→2024
ab45d51faCopyright 2001-2022→2001-2023
5f7ef41b8Copyright 2021→2022
ceb63e8a1Copyright 2001-2021
7c79f192Copyright 2020
73a9755dNettoyage de code dans tous les utilitaires. Blocs catch identiques fusionnés, ArrayList<Class> remplacé par l'opérateur diamant ArrayList<>, StringBuffer remplacé par StringBuilder, Collections.sort remplacé par List.sort. Le code ExceptionHelper lui-même utilise StringBuilder dans getFilteredStackTrace — ce commit a assuré la cohérence avec la migration à l'échelle du projet de StringBuffer synchronisé vers StringBuilder non synchronisé.
Piège — Détection CGLIB$$ : La méthode ignore() vérifie la présence de CGLIB$$ dans le nom de la classe. Lorsque ProjectForge passera à Hibernate 6.x, les proxies utiliseront ByteBuddy au lieu de CGLIB — les noms de classe contiendront $HibernateProxy$ ou $ByteBuddy$ à la place. La méthode ignore() devra être mise à jour pour gérer les deux motifs.