2009-04-10 10 views
15

J'ai créé simple annotation en Javaannotations Java

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.FIELD) 
public @interface Column { 
    String columnName(); 
} 

et classe

public class Table { 

    @Column(columnName = "id") 
    private int colId; 

    @Column(columnName = "name") 
    private String colName; 

    private int noAnnotationHere; 

    public Table(int colId, String colName, int noAnnotationHere) { 
     this.colId = colId; 
     this.colName = colName; 
     this.noAnnotationHere = noAnnotationHere; 
    } 
} 

je dois itérer sur tous les domaines, qui sont annotés avec Column et obtenir nom et valeur de champ et d'annotation. Mais j'ai un problème avec obtenir valeur de chaque champ, car ils sont tous de de type de données différent.

Y a-t-il quelque chose qui retournerait la collection de champs qui ont une certaine annotation? J'ai réussi à le faire avec ce code, mais je ne pense pas que la réflexion soit un bon moyen de le résoudre.

Table table = new Table(1, "test", 2); 

for (Field field : table.getClass().getDeclaredFields()) { 
    Column col; 
    // check if field has annotation 
    if ((col = field.getAnnotation(Column.class)) != null) { 
     String log = "colname: " + col.columnName() + "\n"; 
     log += "field name: " + field.getName() + "\n\n"; 

     // here i don't know how to get value of field, since all get methods 
     // are type specific 

     System.out.println(log); 
    } 
} 

Dois-je envelopper tous les champs objet, ce qui mettrait en œuvre la méthode comme getValue(), ou est-il une meilleure façon de contourner cela? Fondamentalement, tout ce dont j'ai besoin est une représentation sous forme de chaîne de chaque champ qui est annoté.

modifier: yep field.get(table) fonctionne, mais seulement pour les champs public, y a-t-il un moyen de le faire même pour les champs private? Ou dois-je faire getter et en quelque sorte l'invoquer?

+0

setAccessible. La version de tableau sera plus rapide si vous avez un gestionnaire de sécurité présent. setAccessible est, bien sûr, très dangereux dans les situations où vous avez un responsable de la sécurité. –

+0

effrayant ...On dirait que vous implémentez votre propre version de JPA – basszero

+0

@basszero: Oui, vous avez raison, je dois le faire pour mon projet de collège à cause de mon stupide prof qui vit dans une grotte et ne permet pas d'utiliser des bibliothèques telles que Toplink etc ... –

Répondre

11

Chaque objet doit avoir toString() défini. (Et vous pouvez remplacer cela pour chaque classe pour obtenir une représentation plus significative).

Alors vous où votre « // ici, je ne sais pas » comment, vous pourriez avoir:

Object value = field.get(table); 
// gets the value of this field for the instance 'table' 

log += "value: " + value + "\n"; 
// implicitly uses toString for you 
// or will put 'null' if the object is null 
+0

thx, cela fonctionne, mais seulement si les champs sont déclarés publics, quand ils sont privés, je reçois Exception dans le fil "principal" java.lang.IllegalAccessException: Class Main ne peut pas accéder à un membre de la classe Table avec modificateurs "private" –

+0

@Darth - jetez un oeil à Field.setAccessible - http://java.sun.com/javase/6/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible (Booléen) – McDowell

+0

@McDowell - thx qui résout le problème –

9

La réflexion est exactement la façon de le résoudre. Trouver des choses sur les types et leurs membres au moment de l'exécution est à peu près la définition de la réflexion! La façon dont vous l'avez fait me va bien.

Pour trouver la valeur du champ, utilisez field.get(table)

4

La réflexion est exactement la façon de regarder les annotations. Ils sont une forme de "métadonnées" attachées à la classe ou à la méthode, et les annotations Java ont été conçues pour être examinées de cette façon.

+0

Wow, je partage les mêmes 5 premiers mots avec la réponse de Jon, je dois être en train de m'améliorer :) – Uri

+2

Si vous regardez attentivement, vous verrez que M. Skeet a placé son troisième mot 'exactement 'en italique alors que votre entrée est uniquement en format normal non-italique. Bravo pour un pas dans la bonne direction mais sans cette subtile mais si descriptive emphase que Jon a utilisée vos cinq premiers mots encore en deçà de Mr Skeets. –

2

La réflexion est un moyen de traiter l'objet (probablement le seul moyen si les champs sont privés et n'ont pas de méthode d'accès). Vous aurez besoin de regarder Field.setAccessible et peut-être Field.getType.

Une autre approche consiste à générer une autre classe pour énumérer les champs annotés en utilisant un compile-time annotation processor. Cela nécessite une API com.sun dans Java 5, mais la prise en charge est meilleure dans Java 6 JDK (les IDE comme Eclipse peuvent nécessiter une configuration de projet spéciale).

Questions connexes