fbiville / annotation-processing-ftw

Devoxx '15 hands-on lab - Annotation Processing: @​Nailed("it")
MIT License
5 stars 5 forks source link

Niveau 2 #5

Open lesaint opened 9 years ago

lesaint commented 9 years ago

talk

Avec un AP, on peut étendre le compilateur => faire de la validation

lesaint commented 9 years ago

Pour les exos 5 à Z, l'idée est un genre de parcours dirigé des outils dispo et des bonnes pratiques.

Je me dis que pour découvrir l'API javax.lang.model l'idéal est de résoudre quelques problèmes plus petits (genre : récupérez tous les constructeurs de classe A puis class B -- qui sousclasse A, ...) et de s'absoudre de la problématique AP. On donnerai les liens vers les classes ou méthodes à utiliser et les participants n'auraient qu'à compléter une méthode.

Seulement, je ne vois pas trop comment l'écrire en test U. Ces codes ne peuvent être exécutés que dans le contexte d'un AP. L'alternative étant de mocker l'API javax.lang.model, je n'y crois pas.

La seule solution que je vois, c'est d'utiliser un AP dont le rôle est de cracher des messages de compilation produits à partir du résultat du code à écrire. Le test U consisterait alors à vérifier avec compile-testing ce qui est affiché. Encore faut-il que compile-testing le permette. Pour passer d'un test à un autre, je pense soit à avoir plusieurs AP, soit à utiliser les paramètres de l'AP (là aussi, faut vérifier que c'est faisable) pour indiquer quel test exécuter, soit, plus bourrin mais simple, un seul AP exécute toujours tous les tests mais chaque test U ne vérifie qu'un sous ensemble des lignes produits (par exemple, chaque test produit des lignes qui commence par [TEST XX]).

lesaint commented 9 years ago

Idée pour exo 5 à Z :

extraire toutes les méthodes et constructeurs d'une classe (héritée ou non)

code de DAMapping, il faut ignorer la conversion en DAMethod. Contient des sous exercices (liste des classes de la hiérarchie, convertir en TypeElement, ...).

  @Nonnull
  private List<JavaxDAMethod> retrieveMethods(final TypeElement classElement, final JavaxExtractor javaxExtractor) {
    List<TypeElement> classHierarchy = extractClassHierarchyAsList(classElement);

    List<JavaxDAMethod> res = Lists.of();
    for (TypeElement clazz : classHierarchy) {
      if (clazz.getEnclosedElements() == null) {
        continue;
      }

      for (JavaxDAMethod javaxDAMethod : from(clazz.getEnclosedElements())
          // methods are ExecutableElement
          .filter(ExecutableElement.class)
          // filter out super class constructors
          .filter(
              clazz.equals(classElement) ? Predicates.<ExecutableElement>alwaysTrue() : FilterOutConstructor.INSTANCE
          )
          // transform into object of the DAModel
          .transform(new ExecutableElementToJavaxDAMethod(javaxExtractor, classElement))
          .filter(notNull())) {
        res.add(javaxDAMethod);
      }
    }

    return res;
  }

  private static enum FilterOutConstructor implements Predicate<ExecutableElement> {
    INSTANCE;

    @Override
    public boolean apply(@Nullable ExecutableElement executableElement) {
      return executableElement != null && executableElement.getKind() != ElementKind.CONSTRUCTOR;
    }
  }

  private List<TypeElement> extractClassHierarchyAsList(TypeElement classElement) {
    return classElement.accept(new SuperTypeElementsVisitor(), new ArrayList<TypeElement>());
  }

  @Nullable
  private static TypeElement asTypeElement(TypeMirror t) {
    DeclaredType declaredType = asDeclaredType(t);
    if (declaredType == null) {
      return null;
    }
    return declaredType.asElement().accept(AsTypeElementVisitor.INSTANCE, null);
  }

  private static class AsTypeElementVisitor extends SimpleElementVisitor6<TypeElement, Void> {
    public static final AsTypeElementVisitor INSTANCE = new AsTypeElementVisitor();

    private AsTypeElementVisitor() {
      // prevents instantiation
    }

    @Override
    public TypeElement visitType(TypeElement e, Void o) {
      return e;
    }
  }

  @Nullable
  private static DeclaredType asDeclaredType(TypeMirror t) {
    return t.accept(AsDeclaredTypeTypeVisitor.INSTANCE, null);
  }

  private static class AsDeclaredTypeTypeVisitor extends SimpleTypeVisitor6<DeclaredType, Object> {
    public static final AsDeclaredTypeTypeVisitor INSTANCE = new AsDeclaredTypeTypeVisitor();

    private AsDeclaredTypeTypeVisitor() {
      // prevents instantiation
    }

    @Override
    public DeclaredType visitDeclared(DeclaredType t, Object o) {
      return t;
    }
  }

A noter qu'il semble que l'extraction des méthodes aurait pu être codée en exploitant Elements et ElementFilter mais on récupère aussi les méthodes de java.lang.Object (getClass(), equals(), ...). Cependant, on a pas le problème de récupérer le constructeur des super class comme dans le code extrait de DAMapping.

List<? extends Element> allMembers = elementUtils.getAllMembers(classElement);
List<ExecutableElement> executableElements = ElementFilter.methodsIn(allMembers);
lesaint commented 9 years ago

sur la compréhension de Element et Type, extrait de http://docs.oracle.com/javase/7/docs/api/index.html?javax/lang/model/package-summary.html:

In particular, the model makes a distinction between static language constructs, like the element representing java.util.Set, and the family of types that may be associated with an element, like the raw type java.util.Set, java.util.Set, and java.util.Set.

lesaint commented 9 years ago

Je viens de modifier la description de cette issue:

  1. l'exo 4 n'a plus de raison d'être, l'aspect statefull du Processor
    • a déjà été mis en avantau niveau 1 (exo2 étape2, suppression à la bourrin du bégaiement)
    • sera utilisé dans les exercices du niveau3 (génération du fichier des morts de Game Of Thrones par ex.)
  2. comme ce niveau comporte déjà deux exercices assez long qui se concentrent sur l'API, je pense que les autres peuvent être déplacé au niveau 3

@fbiville WDYT ?

lesaint commented 9 years ago

reste à faire :

fbiville commented 9 years ago

Y'a encore des choses à faire ici ? Ton dernier commentaire est toujours d'actualité ?

sns-seb commented 9 years ago

dernier commentaire toujours d'actualité pour le nettoyage de l'historique, descopable pour ce qui est du README (sera couvert à l'oral)