Created
March 17, 2015 21:37
-
-
Save fbiville/988b2aefa6b85de61fdb to your computer and use it in GitHub Desktop.
Level 2 / exo 1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package fr.devoxx.niveau2.exo1.etape2; | |
import java.util.List; | |
import javax.annotation.Nonnull; | |
import javax.lang.model.element.AnnotationMirror; | |
import javax.lang.model.element.Element; | |
import javax.lang.model.util.Elements; | |
import javax.lang.model.util.Types; | |
/** | |
* ClassAnnotationsExplorer - | |
* | |
* @author Sébastien Lesaint | |
*/ | |
public class ClassAnnotationsExplorer { | |
@Nonnull | |
private final Elements elementUtils; | |
@Nonnull | |
private final Types typeUtils; | |
public ClassAnnotationsExplorer(@Nonnull Elements elementUtils, @Nonnull Types typeUtils) { | |
this.elementUtils = elementUtils; | |
this.typeUtils = typeUtils; | |
} | |
/** | |
* Extrait la liste des annotations de la classe sous forme de {@link AnnotationMirror}. | |
* | |
* @param annotatedClassElement le {@link Element} de {@link fr.devoxx.niveau2.exo1.etape2.AnnotatedClass} | |
* | |
* @return une liste contenant un {@link AnnotationMirror} représentant l'annotation {@link fr.devoxx.niveau2.exo1.Flag} | |
* puis un représentant l'annotation {@link Meta} | |
*/ | |
public List<? extends AnnotationMirror> extractAnnotations(@Nonnull Element annotatedClassElement) { | |
return elementUtils.getAllAnnotationMirrors(annotatedClassElement); | |
} | |
/** | |
* Extrait l'annotation {@link Meta} de la classe. | |
* | |
* @param annotatedClassElement le {@link Element} de {@link fr.devoxx.niveau2.exo1.etape2.AnnotatedClass} | |
* | |
* @return l'instance de {@link Meta} sur la classe {@link fr.devoxx.niveau2.exo1.etape2.AnnotatedClass} | |
*/ | |
public Meta extractMetaAnnotation(@Nonnull Element annotatedClassElement) { | |
return annotatedClassElement.getAnnotation(Meta.class); | |
} | |
/** | |
* Extrait la valeur du membre "value" de l'annotation {@link Meta} sur la classe. | |
* | |
* @param annotatedClassElement le {@link Element} de {@link fr.devoxx.niveau2.exo1.etape2.AnnotatedClass} | |
* | |
* @return "La robe est blanc et or, moi je te dis !" | |
*/ | |
public String extractMetaAnnotationValue(@Nonnull Element annotatedClassElement) { | |
return extractMetaAnnotation(annotatedClassElement).value(); | |
} | |
/** | |
* Extrait la valeur du membre "id" de l'annotation {@link fr.devoxx.niveau2.exo1.etape2.Meta} sur la classe à partir | |
* de l'{@link AnnotationMirror} qui représente l'annotation. | |
* <p> | |
* Notez qu'aucune valeur n'est donnée au membre "id" sur la classe | |
* {@link fr.devoxx.niveau2.exo1.etape2.AnnotatedClass}, la valeur récupérée est donc la valeur par défaut. L'API | |
* ne permet pas de savoir si la valeur a été définie explicitement sur la classe | |
* {@link fr.devoxx.niveau2.exo1.etape2.AnnotatedClass} ou pas (mais est-ce important ?). | |
* </p> | |
* | |
* @param annotatedClassElement le {@link Element} de {@link AnnotatedClass} | |
* | |
* @return -99812 | |
*/ | |
public int extractMetaAnnotationId(@Nonnull Element annotatedClassElement) { | |
return extractMetaAnnotation(annotatedClassElement).id(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package fr.devoxx.niveau2.exo1.etape1; | |
import java.lang.reflect.Type; | |
import java.util.Set; | |
import javax.annotation.Nonnull; | |
import javax.lang.model.element.Element; | |
import javax.lang.model.element.Modifier; | |
import javax.lang.model.element.Name; | |
import javax.lang.model.element.PackageElement; | |
import javax.lang.model.element.TypeElement; | |
import javax.lang.model.util.Elements; | |
import javax.lang.model.util.SimpleElementVisitor6; | |
import javax.lang.model.util.Types; | |
/** | |
* ClassDeclarationExplorer - | |
* | |
* @author Sébastien Lesaint | |
*/ | |
public class ClassDeclarationExplorer { | |
@Nonnull | |
private final Elements elementUtils; | |
@Nonnull | |
private final Types typeUtils; | |
public ClassDeclarationExplorer(@Nonnull Elements elementUtils, @Nonnull Types typeUtils) { | |
this.elementUtils = elementUtils; | |
this.typeUtils = typeUtils; | |
} | |
/** | |
* Extrait le nom de la classe à partir du {@link javax.lang.model.element.Element} qui la représente. | |
* | |
* @param basicClassElement le {@link javax.lang.model.element.Element} de | |
* {@link fr.devoxx.niveau2.exo1.etape1.BasicClass} | |
* | |
* @return "BasicClass" sous forme de {@link javax.lang.model.element.Name} | |
*/ | |
public Name extractClassName(@Nonnull Element basicClassElement) { | |
return basicClassElement.getSimpleName(); | |
} | |
/** | |
* Transforme un {@link javax.lang.model.element.Element} en un {@link javax.lang.model.element.TypeElement} si | |
* applicable, autrement retourne {@code null}. | |
* <p> | |
* L'usage de {@code instanceof}, bien que pouvant fonctionner, n'est pas la méthode préconisée par l'API est l'usage | |
* d'un {@link javax.lang.model.element.ElementVisitor} et de | |
* {@link Element#accept(javax.lang.model.element.ElementVisitor, Object)} | |
* (astuce: {@link javax.lang.model.util.SimpleElementVisitor6} fournit un adapteur qui réduira la taille de votre | |
* code). | |
* </p> | |
* | |
* @param element le {@link javax.lang.model.element.Element} de {@link fr.devoxx.niveau2.exo1.etape1.BasicClass} | |
* | |
* @return un {@link javax.lang.model.element.TypeElement} ou {@code null} | |
*/ | |
public TypeElement asTypeElement(@Nonnull Element element) { | |
return element.accept(new SimpleElementVisitor6<TypeElement, Void>() { | |
public TypeElement visitType(TypeElement e, Void ignored) { | |
return e; | |
} | |
}, null); | |
} | |
/** | |
* Extrait le nom qualifié de la classe à partir du {@link javax.lang.model.element.Element} qui la représente. | |
* <p> | |
* Tous les {@link javax.lang.model.element.Element} n'ont pas de nom qualifié, mais c'est le cas du type qui | |
* représente les classes, {@link TypeElement}. | |
* </p> | |
* | |
* @param basicClassElement le {@link javax.lang.model.element.Element} de | |
* {@link fr.devoxx.niveau2.exo1.etape1.BasicClass} | |
* | |
* @return "fr.devoxx.niveau2.exo1.etape1.BasicClass" sous forme de {@link javax.lang.model.element.Name} | |
*/ | |
public Name extractClassQualifiedName(@Nonnull Element basicClassElement) { | |
return asTypeElement(basicClassElement).getQualifiedName(); | |
} | |
/** | |
* Extrait le nom du package de la classe à partir du {@link javax.lang.model.element.TypeElement} qui la | |
* représente. | |
* <p> | |
* Vous pouvez essayer de récupérer le package d'une classe à partir de son {@link TypeElement} en remontant | |
* la hiérarchie des élements via le lien {@link Element#getEnclosingElement()} mais ce besoin est tellement | |
* commun que {@link Elements} propose une méthode {@link Elements#getPackageOf} | |
* </p> | |
* | |
* @param basicClassTypeElement le {@link javax.lang.model.element.TypeElement} de | |
* {@link fr.devoxx.niveau2.exo1.etape1.BasicClass} | |
* | |
* @return "etape1" sous forme de {@link javax.lang.model.element.Name} | |
*/ | |
public PackageElement extractPackage(@Nonnull TypeElement basicClassTypeElement) { | |
return elementUtils.getPackageOf(basicClassTypeElement).accept(new SimpleElementVisitor6<PackageElement, Void>() { | |
public PackageElement visitPackage(PackageElement e, Void ignored) { | |
return e; | |
} | |
}, null); | |
} | |
/** | |
* Extrait le nom qualifié du package de la classe à partir du {@link javax.lang.model.element.TypeElement} qui la | |
* représente. | |
* | |
* @param basicClassTypeElement le {@link javax.lang.model.element.TypeElement} de | |
* {@link fr.devoxx.niveau2.exo1.etape1.BasicClass} | |
* | |
* @return "fr.devoxx.niveau2.exo1.etape1" sous forme de {@link javax.lang.model.element.Name} | |
*/ | |
public Name extractPackageName(@Nonnull TypeElement basicClassTypeElement) { | |
return extractPackage(basicClassTypeElement).getQualifiedName(); | |
} | |
/** | |
* Extrait les "modifiers" de la classe à partir du {@link javax.lang.model.element.TypeElement} qui la | |
* représente. | |
* | |
* @param basicClassTypeElement le {@link javax.lang.model.element.TypeElement} de | |
* {@link fr.devoxx.niveau2.exo1.etape1.BasicClass} | |
* | |
* @return "public" et "final" sous la forme de {@link javax.lang.model.element.Modifier} dans un | |
* {@link java.util.Set} | |
*/ | |
public Set<Modifier> extractModifiers(@Nonnull TypeElement basicClassTypeElement) { | |
return basicClassTypeElement.getModifiers(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package fr.devoxx.niveau2.exo1.etape3; | |
import fr.devoxx.niveau2.exo1.etape1.ClassDeclarationExplorer; | |
import java.util.List; | |
import java.util.stream.Collectors; | |
import javax.annotation.Nonnull; | |
import javax.lang.model.element.Element; | |
import javax.lang.model.element.TypeElement; | |
import javax.lang.model.type.TypeMirror; | |
import javax.lang.model.util.Elements; | |
import javax.lang.model.util.SimpleElementVisitor6; | |
import javax.lang.model.util.Types; | |
/** | |
* ClassInterfacesExplorer - | |
* | |
* @author Sébastien Lesaint | |
*/ | |
public class ClassInterfacesExplorer { | |
@Nonnull | |
private final Elements elementUtils; | |
@Nonnull | |
private final Types typeUtils; | |
private final ClassDeclarationExplorer classDeclarationUtils; | |
public ClassInterfacesExplorer(@Nonnull Elements elementUtils, @Nonnull Types typeUtils) { | |
this.elementUtils = elementUtils; | |
this.typeUtils = typeUtils; | |
classDeclarationUtils = new ClassDeclarationExplorer(this.elementUtils, this.typeUtils); | |
} | |
/** | |
* Extrait les interfaces implémentées par la classe à partir du {@link TypeElement} qui la représente. | |
* | |
* @param implementsInterfacesClassTypeElement le {@link Element} de | |
* {@link fr.devoxx.niveau2.exo1.etape3.ImplementsInterfacesClass} | |
* | |
* @return une liste contenant les {@link TypeMirror} représentant les interfaces {@link java.io.Serializable} et | |
* {@link java.lang.Comparable} implémentées par la classe | |
* {@link fr.devoxx.niveau2.exo1.etape3.ImplementsInterfacesClass} | |
*/ | |
public List<? extends TypeMirror> extractInterfaces(@Nonnull TypeElement implementsInterfacesClassTypeElement) { | |
return implementsInterfacesClassTypeElement.getInterfaces(); | |
} | |
/** | |
* Transforme une liste de {@link TypeMirror} en la liste des {@link TypeElement} qu'ils "référencent". | |
* <p> | |
* (astuce: pour la transformation de {@link TypeMirror} en {@link Element}, la classe {@link Elements} peut | |
* vous aider) | |
* </p> | |
* <p> | |
* (rappel: la tranformation de {@link Element} à {@link TypeElement} a été couverte lors de l'étape 1). | |
* </p> | |
* | |
* @param implementsInterfacesClassTypeElement le {@link TypeElement} de | |
* {@link fr.devoxx.niveau2.exo1.etape3.ImplementsInterfacesClass} | |
* | |
* @return une liste contenant les {@link TypeElement} des interfaces {@link java.io.Serializable} et | |
* {@link java.lang.Comparable} | |
*/ | |
public List<TypeElement> extractInterfaceAsTypeElements(@Nonnull TypeElement implementsInterfacesClassTypeElement) { | |
return extractInterfaces(implementsInterfacesClassTypeElement).stream() | |
.map(mirror -> classDeclarationUtils.asTypeElement(typeUtils.asElement(mirror))) | |
.collect(Collectors.<TypeElement>toList()); | |
} | |
/** | |
* Extrait le {@link TypeMirror} qui représente l'interface {@link java.io.Serializable} à partir du | |
* {@link TypeElement} représentant la classe. | |
* <p> | |
* Pour identifier le bon {@link TypeMirror}, il convient de filtrer sur le nom qualifié de la classe | |
* (ici "java.io.Serializable"). Cette information est portée par le {@link TypeElement} "référencé" par le | |
* {@link TypeMirror}. Les transformations vues lors des exercices prédécents vous seront donc utiles. | |
* </p> | |
* | |
* @param interfaces la liste des {@link TypeMirror} des interfaces implémentées par | |
* {@link fr.devoxx.niveau2.exo1.etape3.ImplementsInterfacesClass} | |
* | |
* @return le {@link TypeElement} qui représente l'interface {@link java.io.Serializable} | |
*/ | |
public TypeMirror extractSerializableInterface(@Nonnull List<? extends TypeMirror> interfaces) { | |
return interfaces.stream() | |
.map(mirror -> typeUtils.asElement(mirror)) | |
.map(classDeclarationUtils::asTypeElement) | |
.filter(element -> classDeclarationUtils.extractClassQualifiedName(element).contentEquals("java.io.Serializable")) | |
.map(element -> element.asType()) | |
.findFirst() | |
.get(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package fr.devoxx.niveau2.exo1.etape4; | |
import fr.devoxx.niveau2.exo1.etape1.ClassDeclarationExplorer; | |
import javax.annotation.Nonnull; | |
import javax.lang.model.element.Element; | |
import javax.lang.model.element.Name; | |
import javax.lang.model.element.TypeElement; | |
import javax.lang.model.element.TypeParameterElement; | |
import javax.lang.model.type.DeclaredType; | |
import javax.lang.model.type.TypeMirror; | |
import javax.lang.model.util.Elements; | |
import javax.lang.model.util.Types; | |
import java.util.List; | |
import java.util.stream.Collectors; | |
/** | |
* ClassSuperClassExplorer - | |
* | |
* @author Sébastien Lesaint | |
*/ | |
public class ClassSuperClassExplorer { | |
@Nonnull | |
private final Elements elementUtils; | |
@Nonnull | |
private final Types typeUtils; | |
private final ClassDeclarationExplorer classDeclarationExplorer; | |
public ClassSuperClassExplorer(@Nonnull Elements elementUtils, @Nonnull Types typeUtils) { | |
this.elementUtils = elementUtils; | |
this.typeUtils = typeUtils; | |
classDeclarationExplorer = new ClassDeclarationExplorer(elementUtils, typeUtils); | |
} | |
/** | |
* @param myListClassTypeElement le {@link TypeElement} de {@link fr.devoxx.niveau2.exo1.etape4.MyListClass} | |
* | |
* @return le {@link TypeMirror} de la déclaration de {@link java.util.ArrayList} comme super classe de | |
* {@link fr.devoxx.niveau2.exo1.etape4.MyListClass} | |
*/ | |
public TypeMirror extractSuperClass(@Nonnull TypeElement myListClassTypeElement) { | |
return typeUtils.directSupertypes(myListClassTypeElement.asType()).iterator().next(); | |
} | |
/** | |
* @param arrayListTypeMirror le {@link TypeMirror} de la déclaration de {@link java.util.ArrayList} comme super | |
* classe de {@link fr.devoxx.niveau2.exo1.etape4.MyListClass} | |
* | |
* @return | |
*/ | |
public DeclaredType asDeclaredType(@Nonnull TypeMirror arrayListTypeMirror) { | |
return (DeclaredType) typeUtils.capture(arrayListTypeMirror); | |
} | |
/** | |
* Extrait le {@link TypeMirror} qui représente l'argument générique de la déclaration de super classe de | |
* {@link fr.devoxx.niveau2.exo1.etape4.MyListClass}. | |
* <p> | |
* L'objectif de cette méthode est d'extraire le {@link TypeMirror} qui représente l'argument générique "String" dans | |
* la déclaration de super classe de {@link fr.devoxx.niveau2.exo1.etape4.MyListClass} : | |
* {@code extends ArrayList<String>"}. Cette information est portée par le {@link TypeMirror} de la super classe | |
* de {@link fr.devoxx.niveau2.exo1.etape4.MyListClass}. | |
* </p> | |
* <p> | |
* Cette méthode et la suivante ont pour objectif de mettre en avant la différence entre un type (classe dans le | |
* package "javax.lang.model.type") et un element (classe dans le package "javax.lang.model.element"). Et pour cela, les | |
* génériques sont l'illustration la plus efficace. | |
* </p> | |
* | |
* @param myListClassTypeElement le {@link TypeElement} de {@link fr.devoxx.niveau2.exo1.etape4.MyListClass} | |
* | |
* @return le {@link TypeMirror} représentant l'argument générique "String" dans la déclaration de super class | |
* {@code extends ArrayList<String>"} | |
*/ | |
public TypeMirror extractSuperClassTypeArgument(@Nonnull TypeElement myListClassTypeElement) { | |
return asDeclaredType(extractSuperClass(myListClassTypeElement)).getTypeArguments().iterator().next(); | |
} | |
/** | |
* Extrait le {@link Name} qui représente le paramètre générique de la super classe de | |
* {@link fr.devoxx.niveau2.exo1.etape4.MyListClass}: {@link java.util.ArrayList}. | |
* <p> | |
* L'objectif de cette méthode est d'extraire le {@link TypeParameterElement} qui représente le paramètre générique | |
* de la classe {@link java.util.ArrayList}. Cette information est portée par le {@link TypeElement} qui représente la | |
* classe {@link java.util.ArrayList}. | |
* </p> | |
* <p> | |
* Cette méthode et la précédente ont pour objectif de mettre en avant la différence entre un type (classe dans le | |
* package "javax.lang.model.type") et un element (classe dans le package "javax.lang.model.element"). Et pour cela, les | |
* génériques sont l'illustration la plus efficace. | |
* </p> | |
* | |
* @param myListClassTypeElement le {@link TypeElement} de {@link fr.devoxx.niveau2.exo1.etape4.MyListClass} | |
* | |
* @return {@link Name} représentant le paramètre générique "E" dans la déclaration de classe de | |
* {@link java.util.ArrayList} | |
*/ | |
public Name extractSuperClassTypeParameterName(@Nonnull TypeElement myListClassTypeElement) { | |
return classDeclarationExplorer.asTypeElement(typeUtils.asElement(extractSuperClass(myListClassTypeElement))) | |
.getTypeParameters() | |
.iterator() | |
.next().getSimpleName(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment