web-dev-qa-db-fra.com

Détection des annotations présentes dans l'objet donné passées dans un constructeur

Ma question en bref: comment détecter si une annotation Java est présente (et au bon endroit) pour une classe/un objet utilisateur donné).

Détails du "problème"

Disons que j'ai deux classes Java:

public class Line {
   private List<Cell> cells;

   public Line(Object... annotatedObjects) {
     // check if annotations @Line and @Cell are present in annotatedObjects.
   }

   // getter/setter for cells.
}

public class Cell {
   // some members
   // some methods
}

Un objet Line contient des cellules.

J'ai également deux annotations, comme:

public @interface Line {
  // some stuff here
}

public @interface Cell {
  // some stuff here
}

J'ai également un tas de classes d'utilisateurs (deux feront pour cet exemple) qui contiennent les annotations @Line et @Cell que j'ai spécifiées, comme:

@Line(name="pqr", schema="three")
public class AUserClass {
   @Cell
   private String aString;
}

@Line(name="xyz", schema="four")
public class AnotherUserClass {
   @Cell(name="birthday")
   private Date aDate;
}

Le problème: lorsque j'instancie un nouvel objet Line, je veux pouvoir passer les classes/objets utilisateur dans le constructeur Line. Le constructeur Line recherche ensuite si les classes/objets utilisateur transmis sont des classes valides qui peuvent être traitées. Seules les classes d'utilisateurs qui ont une annotation @Line Pour la classe et au moins une annotation @Cell Pour ses membres sont des objets valides qui peuvent être passés dans le constructeur de l'objet Line. Tous les autres objets transmis ne sont pas valides. Au moment où un objet utilisateur valide est passé, tous les membres disponibles marqués comme @Cell Dans cet objet sont transformés en objets Cell et ajoutés à la liste des cellules.

Mes questions:

  1. est-il possible de détecter les annotations dans cet objet/classe au moment de l'exécution, et uniquement pour CET objet passé (je ne veux pas rechercher des annotations sur le chemin de classe!)?
  2. est-il possible de détecter le type de données des membres marqués @Cell? Cela est nécessaire car la classe Cell n'accepte pas tous les types de données.
  3. est-il possible de récupérer le nom de membre réel (spécifié dans le Java) afin que l'utilisateur n'ait pas à spécifier le nom de cellule des membres. Je veux que l'utilisateur puisse écrire @Cell (Sans nom) et @Cell(name="aName"), et lorsque seul @Cell Est spécifié, le nom du membre est utilisé à la place. Je ne sais pas si ces informations sont toujours disponibles à l'exécution en utilisant la réflexion.
  4. Comment détecter si les annotations sont au bon endroit? Si le code est balisé comme ceci, alors l'objet doit être ignoré (ou peut-être une exception est levée)?
    @Cell // oh oh, that's no good :(
    public class WrongClass {
    // some members
    }
  5. Pourriez-vous fournir du code de démarrage, donc je connais un peu pour résoudre ce problème. Je suis vraiment nouveau dans les annotations et la réflexion. BTW: j'utilise le dernier jvm 1.6+

Merci pour ton aide!

30
user504342

Vous devez d'abord avoir une politique de rétention sur vos annotations afin de pouvoir les lire avec réflexion

  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.TYPE)
  public static @interface Line {

  }

  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.FIELD)
  public static @interface Cell {

  }

Ensuite, vous devez tester si la classe a l'annotation Line avec isAnnotationPresent(annotationClass). Cette méthode est accessible à partir de Java.lang.Class Et d'un Java.lang.reflect.Field.

NOTE : que vous devez récupérer les champs qui sont privés avec class.getDeclaredField(fieldName).

3. Je ne pense pas que vous puissiez faire une annotation avoir une valeur par défaut basée sur un nom de propriété mais vous pouvez rendre le nom facultatif en fournissant une String name() default DEFAULT par défaut et vérifier cette valeur lors de l'itération à travers le et utilisez la valeur stockée dans name() ou propertyName

43
Liviu T.

Q.1: est-il possible de détecter les annotations dans cet objet/classe lors de l'exécution, et uniquement pour CET objet passé (je ne veux pas rechercher des annotations sur le chemin de classe!)?

Oui, c'est très bien possible en utilisant isAnnotationPresent

@Deprecated
public class AnnotationDetection {

    public static void main(String[] args) {
        AnnotationDetection annotationDetection = new AnnotationDetection();
        System.out.println(annotationDetection.getClass().isAnnotationPresent(Deprecated.class));
    }
}

Notez que les annotations dont la portée est conservée à Runtime seront disponibles uniquement,

20
Jigar Joshi