Publié par
Il y a 6 années · 3 minutes · Java / JEE

Debugger un annotation processor dans un IDE

Cet article est une traduction du billet "Debugging an annotation processor in every IDE" publié sur mon blog.

Durant le dernier HackerGarten, j’ai pu travailler avec Pierre-Yves Ricau sur le projet d’annotation processor "AndroidAnnotations". Si le debugging des annotation processors est plutôt bien documenté pour Eclipse, il ne l’est pas ou très peu pour IntelliJ. Dans cet article, nous comblerons cette lacune en décrivant un mode de debug fonctionnant sous tous environnements confondus.

Tout d’abord, une définition. Un annotation processor est une librairie à ajouter au compilateur javac et qui enrichit notre code source suivant les annotations qui s’y trouvent. Il permet donc d’alléger notre code tout en le rendant plus expressif.

Notons que l’expression "enrichir notre code source" doit être clarifiée. En effet, la JSR-269 n’autorise pas la modification de fichiers source .java. Cependant, il est tout à fait possible d’en créer de nouveaux, tout comme AndroidAnnotations le fait. Il est également possible, mais non standard, de modifier le bytecode généré, comme le fait le projet lombok en utilisant l’API interne de javac.

Les outils pour leur développement ne manquent pas : Eclipse, NetBeans et IntelliJ en ont un bon support. Mais la documentation sur leur debugging fait défaut. Par exemple, pour debugger un annotation processor sous éclipse, les rares pages mentionnent la création d’un plugin eclipse.

Durant le HackerGarten, nous avons opté pour une approche différente : puisque l’annotation processor est une librairie ajoutée au compilateur, si nous parvenons à lancer le compilateur javac en mode debug et à nous y connecter, le tour est joué.

Ajout de l’Annotation Processor (AP) au compilateur

Une fois le projet importé dans IntelliJ, nous pouvons d’ores et déjà ajouter l’annotation processor au process de compilation. Dans le cas d’AndroidAnnotations, nous l’activons en spécifiant le nom complet de la classe (FQN – fully-qualified name) et le module functionnal-test-1-5. Pour cela, il ne faut pas oublier de spécifier un dossier de sortie relatif à la racine du module, ici target/processed.

Vérification de l’AP

Lorsque nous passons la classe BeanInjectedActivity.java à l’annotation processor, nous constatons qu’une classe BeanInjectedActivity_.java est bien générée dans le dossier target/processed et qu’elle est enrichie

Passage du compilateur en mode debug

Nous pouvons passer une instance de JVM en mode debug à l’aide de quelques options dont -Xdebug. Dans notre cas, la commande javac n’est pas en elle-même une instance de la JVM et n’accepte donc pas ces options.

En revanche, javac crée une instance de la JVM dans laquelle le compilateur exécute le travail de compilation, et nous permet d’y envoyer des options en utilisant le paramètre -J :

-J option
Pass option to the java launcher called by javac. For example, -J-Xms48m sets
the startup memory to 48 megabytes. It is a common convention for -J to pass
options to the underlying VM executing applications written in Java.

Nous pouvons donc utiliser les options -J-Xdebug -J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005 pour lancer le compilateur javac en mode debug. Nous ajoutons donc ces options dans IntelliJ et définissons un breakpoint dans la méthode init de la classe AndroidAnnotationProcessor.

 

Ajout d’une configuration et debugging

Nous pouvons maintenant ajouter une configuration de debugging pour le port 5005 dans IntelliJ et relancer l’annotation processor sur la classe BeanInjectedActivity.java. Le processus de compilation bloque sur la phase "make", ce qui indique que le compilateur attend la connexion d’un debugger. Nous pouvons alors lancer le debugger d’intelliJ et constater que :

  • le compilateur s’arrête au breakpoint de la classe AndroidAnnotationProcessor
  • la stacktrace mentionne bien le compilateur javac

Conclusion

Nous avons vu comment le compilateur javac lui-même pouvait être utilisé en mode debug. La technique exposée ici a un avantage majeur : elle fonctionne quel que soit l’IDE utilisé, à compter que les paramètres du compilateur puissent être modifiés.

Pierre Laporte
Pierre est un touche-à-tout chez Xebia qui aime relever tous types de challenges. Des problématiques d'architecture aux tests de charge en passant par la gestion de dette technique ou encore les applications mobiles, c'est poussé par cette volonté d'apprendre qu'il oeuvre aujourd'hui chez Xebia. Il aime faire du code propre et expressif, apprécie le travail d'équipe et se concentre avant tout sur le service rendu à l'utilisateur final.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *