Skip to content

Instantly share code, notes, and snippets.

@fbiville
Created March 17, 2015 21:35
Show Gist options
  • Save fbiville/b9bfd232beaa719e8ebb to your computer and use it in GitHub Desktop.
Save fbiville/b9bfd232beaa719e8ebb to your computer and use it in GitHub Desktop.
Level 2 / exo 2
package fr.devoxx.niveau2.exo2.etape3;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
/**
* DeepExplorer -
*
* @author Sébastien Lesaint
*/
public class DeepExplorer {
@Nonnull
private final Elements elementUtils;
@Nonnull
private final Types typeUtils;
public DeepExplorer(@Nonnull Elements elementUtils, @Nonnull Types typeUtils) {
this.elementUtils = elementUtils;
this.typeUtils = typeUtils;
}
/**
* Extrait la liste des méthodes définies par la classe {@link fr.devoxx.niveau2.exo2.etape3.Employee} ainsi que
* celles héritées de {@link fr.devoxx.niveau2.exo2.etape3.Citizen} et {@link java.lang.Object}.
* <p>
* (astuce: un {@link javax.lang.model.element.ElementVisitor} bien écrit peut résoudre le problème mais il est plus
* simple de jeter un oeil {@link javax.lang.model.util.Elements})
* </p>
*
* @param employeeTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape3.Employee}
*
* @return la liste des méthodes de {@link fr.devoxx.niveau2.exo2.etape3.Employee} plus celles héritées de
* {@link fr.devoxx.niveau2.exo2.etape3.Citizen} et {@link java.lang.Object} sous forme de {@link ExecutableElement}
*/
public List<ExecutableElement> extractAllMethods(@Nonnull TypeElement employeeTypeElement) {
List<? extends Element> allMembers = elementUtils.getAllMembers(employeeTypeElement);
return ElementFilter.methodsIn(allMembers);
}
/**
* Extrait la liste des méthodes héritées par la classe {@link fr.devoxx.niveau2.exo2.etape3.Employee}.
* <p>
* (indice: le {@link javax.lang.model.element.Element} retourné par la méthode
* {@link javax.lang.model.element.ExecutableElement#getEnclosingElement()} d'une méthode est la classe qui la
* définie)
* </p>
* <p>
* (remarque: comme indiqué dans la Javadoc de {@link javax.lang.model.element.Element}, deux instances doivent
* être comparée par leur méthode {@link java.lang.Object#equals(Object)}).
* </p>
*
* @param employeeTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape3.Employee}
*
* @return la méthode {@link fr.devoxx.niveau2.exo2.etape3.Citizen#sayGoodbye()} et les méthodes
* {@link java.lang.Object} sous forme de {@link ExecutableElement}
*/
public List<ExecutableElement> extractInheritedMethods(@Nonnull TypeElement employeeTypeElement) {
return extractAllMethods(employeeTypeElement).stream()
.filter(method -> !method.getEnclosingElement().equals(employeeTypeElement))
.collect(Collectors.toList());
}
/**
* Extrait la liste des méthodes héritées par la classe {@link fr.devoxx.niveau2.exo2.etape3.Employee} à l'exception
* de celles héritées de {@link java.lang.Object}.
* <p>
* (astuce: une instance de {@link javax.lang.model.element.Element} représentant n'importe qu'elle classe/interface
* disponible dans le class loader du Processor peut être récupérée grâce à la méthode
* {@link javax.lang.model.util.Elements#getTypeElement(CharSequence)})
* </p>
*
* @param employeeTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape3.Employee}
*
* @return la liste des méthodes de {@link fr.devoxx.niveau2.exo2.etape3.Employee} et celles héritées
* {@link fr.devoxx.niveau2.exo2.etape3.Citizen} sous forme de {@link ExecutableElement}
*/
public List<ExecutableElement> extractInheritedMethodsButObjects(@Nonnull TypeElement employeeTypeElement) {
return extractInheritedMethods(employeeTypeElement).stream()
.filter(method -> !method.getEnclosingElement().equals(elementUtils.getTypeElement("java.lang.Object")))
.collect(Collectors.toList());
}
}
package fr.devoxx.niveau2.exo2.etape2;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
/**
* FieldsExplorer -
*
* @author Sébastien Lesaint
*/
public class FieldsExplorer {
@Nonnull
private final Elements elementUtils;
@Nonnull
private final Types typeUtils;
public FieldsExplorer(@Nonnull Elements elementUtils, @Nonnull Types typeUtils) {
this.elementUtils = elementUtils;
this.typeUtils = typeUtils;
}
/**
* Extrait la liste des champs définis par la classe {@link fr.devoxx.niveau2.exo2.etape2.Cow} à partir du
* {@link TypeElement} qui la représente.
* <p>
* Les méthodes, constructors, champs sont des elements contenus dans l'élément de la classe.
* </p>
* <p>
* (astuce: connaissez-vous la classe {@link javax.lang.model.util.ElementFilter} ?)
* </p>
*
* @param cowTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape2.Cow}
*
* @return la liste des champs de la classe sous forme de {@link javax.lang.model.element.VariableElement}
*/
public List<VariableElement> extractFields(@Nonnull TypeElement cowTypeElement) {
return ElementFilter.fieldsIn(cowTypeElement.getEnclosedElements());
}
/**
* Extrait le type du champs "name" définis par la classe {@link fr.devoxx.niveau2.exo2.etape2.Cow} à partir du
* {@link TypeElement} qui la représente.
* <p>
* (astuce: la méthode {@link javax.lang.model.element.Name#contentEquals(CharSequence)} est bien pratique)
* </p>
*
* @param cowTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape2.Cow}
*
* @return le {@link TypeMirror} de {@link java.lang.String} pour le champs "name" dans la classe
* {@link fr.devoxx.niveau2.exo2.etape2.Cow}.
*/
public TypeMirror extractNameFieldType(@Nonnull TypeElement cowTypeElement) {
return extractFields(cowTypeElement).stream()
.filter(field -> field.getSimpleName().contentEquals("name"))
.map(Element::asType)
.findFirst()
.get();
}
/**
* Extrait les champs privés ou sans attribut de visibilité définis par la classe
* {@link fr.devoxx.niveau2.exo2.etape2.Cow} à partir du {@link TypeElement} qui la représente.
*
* @param cowTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape2.Cow}
*
* @return la liste des champs privés ou package protected de la classe sous la forme de {@link VariableElement}s
*/
public List<VariableElement> extractPrivateAndPackageProtectedFields(@Nonnull TypeElement cowTypeElement) {
return extractFields(cowTypeElement).stream()
.filter(
field -> {
Set<Modifier> modifiers = field.getModifiers();
return !modifiers.contains(Modifier.PROTECTED) &&
!modifiers.contains(Modifier.PUBLIC);
}
).collect(Collectors.toList());
}
/**
* Extrait les champs dépréciés définis par la classe {@link fr.devoxx.niveau2.exo2.etape2.Cow} à partir du
* {@link TypeElement} qui la représente.
*
* @param cowTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape2.Cow}
*
* @return la liste des champs déprécié de la classe sous la forme de {@link VariableElement}s
*/
public List<VariableElement> extractDeprecatedField(@Nonnull TypeElement cowTypeElement) {
return extractFields(cowTypeElement).stream()
.filter(field -> field.getAnnotation(Deprecated.class) != null)
.collect(Collectors.toList());
}
}
package fr.devoxx.niveau2.exo2.etape1;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
/**
* MethodsExplorer -
*
* @author Sébastien Lesaint
*/
public class MethodsExplorer {
@Nonnull
private final Elements elementUtils;
@Nonnull
private final Types typeUtils;
public MethodsExplorer(@Nonnull Elements elementUtils, @Nonnull Types typeUtils) {
this.elementUtils = elementUtils;
this.typeUtils = typeUtils;
}
/**
* Extrait la liste des méthodes définies par la classe {@link fr.devoxx.niveau2.exo2.etape1.Homer} à partir du
* {@link TypeElement} qui la représente.
* <p>
* Les méthodes, fonctions, champs sont des elements contenus dans l'élément de la classe (ou de l'interface,
* d'ailleurs).
* </p>
* <p>
* (astuce: connaissez-vous la classe {@link javax.lang.model.util.ElementFilter} ?)
* </p>
*
* @param homerTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape1.Homer}
*
* @return la liste des méthodes (ie. pas les constructeurs) sous forme de {@link ExecutableElement}
*/
public List<ExecutableElement> extractMethods(@Nonnull TypeElement homerTypeElement) {
return ElementFilter.methodsIn(homerTypeElement.getEnclosedElements());
}
/**
* Extrait la liste des constructeurs (en fait, un seul) définis par la classe
* {@link fr.devoxx.niveau2.exo2.etape1.Homer} à partir du {@link TypeElement} qui la représente.
* <p>
* (astuce: avez-vous bien regardé la classe {@link javax.lang.model.util.ElementFilter} ?)
* </p>
*
* @param homerTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape1.Homer}
*
* @return une liste contenant le constructeur de {@link fr.devoxx.niveau2.exo2.etape1.Homer} sous forme de
* {@link ExecutableElement}
*/
public List<ExecutableElement> extractConstructors(@Nonnull TypeElement homerTypeElement) {
return ElementFilter.constructorsIn(homerTypeElement.getEnclosedElements());
}
/**
* Extrait la liste des constructeurs et méthodes publiques définis par la classe
* {@link fr.devoxx.niveau2.exo2.etape1.Homer} à partir du {@link TypeElement} qui la représente.
* <p>
* (astuce: les attributs sont définis au niveau de l'interface {@link javax.lang.model.element.Element})
* </p>
*
* @param homerTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape1.Homer}
*
* @return une liste contenant toutes les méthodes et constructeurs publiques de
* {@link fr.devoxx.niveau2.exo2.etape1.Homer} sous forme de {@link ExecutableElement}
*/
public List<ExecutableElement> extractPublicMethodsAndConstructors(@Nonnull TypeElement homerTypeElement) {
return Stream.concat(
extractConstructors(homerTypeElement).stream(),
extractMethods(homerTypeElement).stream().filter(method -> method.getModifiers().contains(Modifier.PUBLIC))
).collect(Collectors.toList());
}
/**
* Extrait la liste des méthodes et constructeurs publics définis par la classe qui retournent {@code void}
* {@link fr.devoxx.niveau2.exo2.etape1.Homer} à partir du {@link TypeElement} qui la représente.
*
* @param homerTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape1.Homer}
*
* @return une liste contenant tous les fonctions publiques de {@link fr.devoxx.niveau2.exo2.etape1.Homer} sous forme
* de {@link ExecutableElement}
*/
public List<ExecutableElement> extractPublicFunctions(@Nonnull TypeElement homerTypeElement) {
return extractPublicMethodsAndConstructors(homerTypeElement).stream()
.filter(method -> method.getReturnType().getKind() == TypeKind.VOID)
.collect(Collectors.toList());
}
/**
* Extrait les méthodes "eatDonuts" définies par la classe {@link fr.devoxx.niveau2.exo2.etape1.Homer} à partir du
* {@link TypeElement} qui la représente.
*
* @param homerTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape1.Homer}
*
* @return une liste contenant le constructeur de {@link fr.devoxx.niveau2.exo2.etape1.Homer} sous forme de
* {@link ExecutableElement}
*/
public List<ExecutableElement> extractEatDonutsMethods(@Nonnull TypeElement homerTypeElement) {
return extractMethods(homerTypeElement).stream()
.filter(method -> method.getSimpleName().contentEquals("eatDonuts"))
.collect(Collectors.toList());
}
/**
* Extrait la méthode "eatDonuts" non dépréciée définie par la classe {@link fr.devoxx.niveau2.exo2.etape1.Homer} à
* partir du {@link TypeElement} qui la représente.
*
* @param homerTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape1.Homer}
*
* @return le {@link ExecutableElement} qui représente la surcharge non dépréciée de la méthode "eatDonuts"
*/
public ExecutableElement extractCurrentEatDonutsMethod(@Nonnull TypeElement homerTypeElement) {
return extractEatDonutsMethods(homerTypeElement).stream()
.filter(method -> method.getAnnotation(Deprecated.class) == null)
.findFirst()
.get();
}
/**
* Extrait les paramètres portant l'annotation {@link javax.annotation.Nullable} des méthodes définies par la classe
* {@link fr.devoxx.niveau2.exo2.etape1.Homer} à partir du {@link TypeElement} qui la représente.
* <p>
* (indice: on peut obtenir le {@link TypeMirror} de tout {@link Element} via la méthode {@code asType()})
* </p>
*
* @param homerTypeElement le {@link TypeElement} de la class {@link fr.devoxx.niveau2.exo2.etape1.Homer}
*
* @return un Set contenant le {@link TypeMirror} de {@link java.lang.String} et
* {@link fr.devoxx.niveau2.exo2.etape1.Homer.Flavor}
*/
public Set<TypeMirror> extractTypeOfNullableParameters(@Nonnull TypeElement homerTypeElement) {
return extractMethods(homerTypeElement).stream()
.flatMap(method -> method.getParameters().stream())
.filter(param -> param.getAnnotation(Nullable.class) != null)
.map(Element::asType)
.collect(Collectors.toSet());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment