pluggable annotation processing api
TRANSCRIPT
![Page 1: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/1.jpg)
PLUGGABLE ANNOTATIONPROCESSING APIJUG TOULOUSE - 2015 - LTE CONSULTING
![Page 2: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/2.jpg)
ARNAUD TOURNIERArchiDév passionné chez LTE Consulting
Speaker Devoxx, GWT.create, Paris/Toulouse JUG, etc...
@ltearno www.lteconsulting.fr
Développement - Formation - Conseil
Full stack (x86_64 to JavaScript) !
![Page 3: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/3.jpg)
AVANT TOUTCette présentation est disponible sur
github.com/ltearno/annotation-processing
Des hyper-liens sont présents
![Page 4: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/4.jpg)
JSR 269 ???
![Page 5: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/5.jpg)
PLUGGABLE ANNOTATIONPROCESSING API...
![Page 6: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/6.jpg)
La JSR 269 - Pluggable Annotation Processing API permetd'exploiter les annotations présentes dans le code en
s'insérant dans le processus de compilation, et de générer denouvelles sources.
Traitement des annotations à la compilation,Génération de code,Génération de fichiers de configuration,Documentation, Cartographie,Vérifications, Build breakers,etc...
On ne modifie pas les sources existants !
![Page 7: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/7.jpg)
AVANTAGES
![Page 8: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/8.jpg)
Le code généré est visible.
Pas de traitement au runtime donc pas d'impact sur lesperformances.
Pas d'instrumentation du byte-code, donc plus simple.
![Page 9: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/9.jpg)
BRÈVE HISTOIRE DUTRAITEMENT DES
ANNOTATIONS
![Page 10: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/10.jpg)
COMMENTAIRES JAVADOCXDoclet (2002)
/***** Account entity bean** @ejb.bean* name="bank/Account"* jndi-name="ejb/bank/Account"* primkey-field="id"* schema = "Customers"* ...*/public class MonBean { ... }
![Page 11: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/11.jpg)
APT, retiré officiellement avec Java 7
car .Annotation Processing Tool
non extensible à Java > 5
Outil lancé en dehors de la compilation.
L'API Mirror utilise les packages com.sun.mirror.
![Page 12: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/12.jpg)
PLUGGABLE ANNOTATION PROCESSING APIDepuis 2006 (Java 6) la , créé par Joe Darcy.JSR-269
Intégré à la compilation javac.
![Page 13: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/13.jpg)
PRINCIPE
![Page 14: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/14.jpg)
On fournit un processeur d'annotation,Le compilateur gère des rounds de processing,A chaque round, les nouveaux sources sont traités (phasesParse et Enter),Les processeurs sont choisis et reçoivent l'AST des classestraitées,Les processeurs peuvent générer de nouveaux fichiers(sources, classes et resources) qui seront parsés et traités auround suivant.
![Page 15: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/15.jpg)
UTILISATION
![Page 16: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/16.jpg)
CRÉATION DE L'ANNOTATIONimport java.lang.annotation.*;
// package, class, method, ...@Target( value = { ElementType.METHOD } )@Retention( RetentionPolicy.SOURCE )public @interface MonAnnotation{ ...}
![Page 17: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/17.jpg)
LE PROCESSEUR@SupportedAnnotationTypes( value= { "fr.lteconsulting.MonAnnotation" } )@SupportedSourceVersion( SourceVersion.RELEASE_6 )public class MonAnnotationProcessor extends AbstractProcessor { @Override public boolean process( Set<?> extends TypeElement> annotations, RoundEnvironment roundEnv ) { Types typeUtils = processingEnv.getTypeUtils(); Elements elementUtils = processingEnv.getElementUtils(); Messager messager = processingEnv.getMessager();
for ( TypeElement element : roundEnv.getElementsAnnotatedWith(MonAnnotation processingEnv.getMessager().printMessage( Diagnostic.Kind.NOTE, element.getQualifiedName()); return true; }}
![Page 18: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/18.jpg)
LE FICHIER SPIPour packager et activer un processeur, le plus simple est
d'utiliser SPI :
Le fichierMETA-INF/services/javax.annotation.processing.Processor
contient la liste des processeurs :
fr.lteconsulting.MyAnnotationProcessor
Packager le tout dans un jar
![Page 19: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/19.jpg)
UN BOUT DE CODEDans un autre projet on peut utiliser l'annotation et le
processeur.
class UneClasse { @MonAnnotation void uneMethode() { ... }}
![Page 20: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/20.jpg)
PACKAGING ET COMPILATIONLe processeur et le fichier SPI sont dans un jar.
Ce jar est dans le class path au moment de la compilation deUneClasse.java.
C'est tout !
![Page 21: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/21.jpg)
SORTIE DE NOTRE EXEMPLEAt line 90 of UneClasse.java :fr.lteconsulting.UneClasse.uneMethode()
![Page 22: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/22.jpg)
FONCTIONNEMENT
![Page 23: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/23.jpg)
A chaque round, le processeur doit traiter les classesgénérées au round précédent.
S'il est appelé au premier round, il le sera pour les autres,jusqu'au dernier round (même si aucune annotation n'est
présente pour lui).
![Page 24: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/24.jpg)
DÉCOUVERTE DES PROCESSEURSLes proceseurs sont découverts par le compilateur.
JavaCompiler fournit des options pour contrôler l'ensembledes processeurs disponibles :
une liste prédéfinie,un chemin de recherche,utiliser SPI.
![Page 25: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/25.jpg)
CHOIX DU PROCESSEURAppel des processeurs en fonction :
des annotations présentes dans les classes traitées,les annotations supportées par les processeurs,le fait qu'un processeur ait claimé une annotation.
![Page 26: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/26.jpg)
CYCLE DE VIE DU PROCESSEURLe compilateur instancie le processeur,Appelle init avec un ProcessingEnvironment,Appelle getSupportedAnnotationTypes,getSupportedOptions etgetSupportedSourceVersion,Et appelle process à chaque round.
![Page 27: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/27.jpg)
A CHAQUE ROUNDjavac calcule l'ensemble des annotations sur les classes encours,si au moins une annotation est présente, au fur et à mesureque les processeurs les claime, elles sont retirées desannotations non matchées.quand l'ensemble est vide ou qu'il n'y a plus de processeurcandidat, le round est fini.si aucune annotation n'est présente, seuls les processeursuniversels ("*") sont appelés, et reçoivent un ensemble videde classes à traiter.
![Page 28: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/28.jpg)
PRÉCAUTIONS !Un processeur ne doit pas dépendre d'un autre,Idempotent,Commutatif.
![Page 29: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/29.jpg)
L'INTERFACE PROCESSORjavax.annotation.processing.Processor
interface Processor { void init( ProcessingEnvironment processingEnv );
Set<String> getSupportedAnnotationTypes();
boolean process( Set<? extends TypeElement> annotations, RoundEnvironment roundEnv );}
![Page 30: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/30.jpg)
PROCESSINGENVIRONMENTjavax.annotation.processing.ProcessingEnvironment
// UtilitairesElements getElementUtils();Types getTypeUtils();Locale getLocale();Map<String, String> getOptions();SourceVersion getSourceVersion();
// Création de fichiersFiler getFiler();
// Affichage utilisateurMessager getMessager();
// Autres classes :// ElementFilter, AbstractVisitors...
![Page 31: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/31.jpg)
GETSUPPORTEDANNOTATIONTYPES*fr.lteconsulting.annotations.*fr.lteconsulting.annotations.MonAnnotation
![Page 32: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/32.jpg)
LA MÉTHODE PROCESSboolean process( Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)
On reçoit l'ensemble des annotations à traiter,On retourne true pour claimer les annotations etempêcher les autres processeurs de les traiter.
![Page 33: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/33.jpg)
ROUNDENVIRONMENTjavax.annotation.processing.RoundEnvironment
Liste des classes dans le round :
Set<? extends Element> getRootElements()
Liste des éléments annotés :
Set<? extends Element> getElementsAnnotatedWith(TypeElement a)Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a)
Etat du round :
// si donne 'true', il ne faut rien générerboolean isProcessingOver()
![Page 34: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/34.jpg)
ELEMENTjavax.lang.model.element.Element
Représente un package, une classe, une méthode, ...
Pour parcourir les données d'un élément, il faut soit appelergetKind() soit utiliser un visiteur.
Ne pas utiliser instanceof !
Petit exercice : POURQUOI ?
![Page 35: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/35.jpg)
ELEMENT// Visiter l'élément :<R,P> R accept(ElementVisitor<R,P> v, P p);
// Obtenir le type :TypeMirror asType();
// Demander la sorte :ElementKind getKind();
// Demander les annotations présentes sur l'élément :List<? extends AnnotationMirror> getAnnotationMirrors();<A extends Annotation> A getAnnotation(Class<A> annotationType);
// Autres :// getModifiers(); getSimpleName(); getEnclosingElement(); getEnclosedElements();
![Page 36: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/36.jpg)
LES SORTES D'ELEMENTElementKind
annotation, class, constructeur, enum, une constante enum,parametre d'exception, champ, initializeur d'instance, interface,
variable locale, méthode, package, paramètre, variable deresource, initializeur statique, paramètre de type, autres (futur).
![Page 37: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/37.jpg)
LE FILERjavax.annotation.processing.Filer
![Page 38: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/38.jpg)
CRÉER UN NOUVEAU SOURCE JAVAFiler filer = processingEnv.getFiler();JavaFileObject jfo = filer.createSourceFile( classElement.getQualifiedName() + "Info");PrintWriter pw = new PrintWriter( jfo );...
![Page 39: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/39.jpg)
CRÉER UNE NOUVELLE RESSOURCEFiler filer = processingEnv.getFiler();try { PrintWriter pw = new PrintWriter(filer.createResource( StandardLocation.SOURCE_OUTPUT, "fr.lteconsulting", "Todo.txt") .openOutputStream()); pw.println("Quelque chose"); pw.close();} catch (IOException ioe) { messager.printMessage(Kind.ERROR, ioe.getMessage());}
![Page 40: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/40.jpg)
CRÉER UN NOUVEAU FICHIER .CLASSFiler filer = processingEnv.getFiler();JavaFileObject jfo = filer.createClassFile( classElement.getQualifiedName() + "Info");PrintWriter pw = new PrintWriter( jfo );...
![Page 41: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/41.jpg)
UTILISATION DE TEMPLATES !Ne générer que le minimum de code !Velocity, ...Java Poet, ...
![Page 42: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/42.jpg)
LE MESSAGERmessager.printMessage( Kind.ERROR, "Cannot find an ID field !" );
// sortie :error: At Book.java, line 12 : Cannot find an ID field !1 error
![Page 43: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/43.jpg)
LE MESSAGER DANS ECLIPSE
La même erreur dans Eclipse
![Page 44: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/44.jpg)
LA COMPILATION JAVA
![Page 45: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/45.jpg)
3 PHASES
Plan d'exécution de javacParse et EnterAnnotation ProcessingAnalyse et Generate
openjdk.java.net/groups/compiler/doc/compilation-overview
![Page 46: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/46.jpg)
JAVACAction Paramètres
Générationdes sources
-s répertoire
Désigner unprocesseur
-processorfr.lteconsulting.MyAnnotationProcessor,autre...
Spécifier unchemin derecherche
-processorPath le_chemin
Passer desoptions
-Acle=valeur
![Page 47: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/47.jpg)
JAVAC (SUITE)Action Paramètres
Désactiver l'AP -proc:none
Seulement l'AP -proc:only
Chemin de recherche dessources
-sourcePath
Désactiver la génération des.class implicite
-implicit:none
Répertoire de sortie des.class
-d
Affichage debug -XprintRounds -XprintProcessorInfo
![Page 48: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/48.jpg)
ATTENTION : le warning si on ne met pas -implicit:none
docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#searching
![Page 49: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/49.jpg)
INTÉGRATION AVECECLIPSE
![Page 50: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/50.jpg)
CONFIGURATIONEclipse utilise son propre compilateur, JDT.
Configuration possible du projet par m2e
![Page 51: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/51.jpg)
![Page 52: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/52.jpg)
ATTENTIONDans Eclipse, si le projet contenant le processeur est ouvert,
l'annotation processing est désactivé.
![Page 53: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/53.jpg)
TESTS UNITAIRES
![Page 54: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/54.jpg)
EXEMPLEJavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// JDK Sun : task peut être casté en com.sun.source.util.JavacTaskCompilationTask task = compiler.getTask( null, // Default log (stderr) fileManager, // (InMemory)JavaFileManager diagnosticCollector, // DiagnosticCollector options, // Set<String> new HashSet<String>(), // Classes pour annotation processing sources); // Iterable<? extends JavaFileObject>
// Force les processeurstask.setProcessors(processors);
boolean successful = task.call(); // succès ou échecdiagnosticCollector.getDiagnostics(); // logs structurés de compilationfileManager.getOutputFiles(); // fichiers de sortie
![Page 55: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/55.jpg)
COMPILE-TESTINGBibliothèque de test développée par Google, pour aider le
développement de et Auto Dagger
![Page 56: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/56.jpg)
Test positif
assert_().about(javaSource()) .that(JavaFileObjects.forResource("HelloWorld.java")) .processedWith(new MyAnnotationProcessor()) .compilesWithoutError() .and() .generatesSources(JavaFileObjects.forResource("GeneratedHelloWorld.java"
![Page 57: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/57.jpg)
et négatif
JavaFileObject fileObject = JavaFileObjects.forResource("HelloWorld.java"assert_().about(javaSource()) .that(fileObject) .processedWith(new NoHelloWorld()) .failsToCompile() .withErrorContaining("No types named HelloWorld!") .in(fileObject) .onLine(23) .atColumn(5);
![Page 58: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/58.jpg)
DÉMO TIME !
![Page 59: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/59.jpg)
LIMITATIONS
![Page 60: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/60.jpg)
Pas d'accès à l'AST complet (corps des méthodes)Pas possible de modifier des classes existantesCertains bug ne permettent pas de traiter correctement lesgénériquesJava et les IDE ne surveillent que les éléments annotéspour redéclencher le processing (parfois problématiquelorsque l'on a des dépendances complexes -> Alt+F5 !)
![Page 61: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/61.jpg)
HACKING AU DELÀ : de bons hacks pour accéder à l'implémentation
(javac de sun et jdt) et modifier l'ASTImmutables : quelques workarounds captant lesimplementations JDK / JDT pour gérer les génériquesExplications techniques générales dans
Lombok
The Hacker's guideto JavaC
![Page 62: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/62.jpg)
EXEMPLES DEBIBLIOTHÈQUES
![Page 63: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/63.jpg)
JPA meta-model generation (JSR-317),Dagger,Google Auto,Immutables,Hexa Binding,Lombok,GWT (RequestFactory)
![Page 64: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/64.jpg)
LIENS EN VRAC
![Page 65: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/65.jpg)
, , , , , , ,
, , , ,
, , , ,
Hibernate Validation JM Doudoux Lombok How Lombokworks ? Lombok encore... Hacking JavaC HexaBinding
Coders Breakfast Prez d'Angelika Langer Dr. Macphail'strance Créez et utilisz vos annotations Histoire des
annotation processing 4 vidéos sur Parleys Utilisation de laJSR-269 chez Les Furets Save method parameter names Au
JUG Paris par Olivier Croisier...
![Page 66: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/66.jpg)
ET VOILÀ !
![Page 67: Pluggable annotation processing api](https://reader031.vdocuments.mx/reader031/viewer/2022021507/58f181e31a28ab4e468b465b/html5/thumbnails/67.jpg)
MERCI !Rendez-vous sur
github.com/ltearno/annotation-processing
Twitter : @ltearno
LinkedIn : fr.linkedin.com/in/lteconsulting
LTE Consulting