27 votes

Cas d'utilisation pour l'implémentation d'annotations

Quelles sont valables cas d'utilisation pour la mise en œuvre des annotations?

Lors de la conception principalement annotation en fonction de la configuration des systèmes j'ai parfois besoin de créer des classes qui mettent en œuvre des annotations pour la génération de code par programmation ou de configuration.

L'alternative consiste à la mise en miroir des données contenues dans les annotations dans l'Otd, ce qui semble être un rétroprojecteur.

Voici un exemple:

public enum IDType {
    LOCAL,
    URI,
    RESOURCE;
}

@Documented
@Target( { METHOD, FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Id {
    /**
     * @return
     */
    IDType value() default IDType.LOCAL;
}

avec la mise en œuvre

public class IdImpl implements Id{

    private final IDType idType;

    public IdImpl(IDType idType){
        this.idType = idType;
    }

    @Override
    public IDType value() {
        return idType;
    }

    @Override
    public Class<? extends Annotation> annotationType() {
        return Id.class;
    }

}

Je reçois des avertissements du compilateur pour cela, mais il semble être un outil valable pour de nombreux cas d'utilisation.

L'avertissement pour l'exemple ci-dessus est

L'annotation de type Id ne doit pas être utilisé comme un superinterface pour IdImpl

Modifié :

Je viens de trouver cet exemple de Guice :

bind(CreditCardProcessor.class)
    .annotatedWith(Names.named("Checkout"))
    .to(CheckoutCreditCardProcessor.class);

Voir ce Javadoc de Noms.

Quelqu'un a quelques informations pourquoi cette restriction existe ou a un autre cas d'utilisation à l'esprit?

13voto

Arne Points 6797

Je n'ai jamais utilisé, dans la pratique, mais ce que vous obtenez est que vous pouvez utiliser les classes, en remplacement de vos annotations.

Nous allons créer un exemple artificiel. Dire que nous avons un générateur de documentation. Il lit un @Docu d'annotation à partir des classes et imprime l' description d'attribut. Comme ceci:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;

public class DokuGenerator {

    public static void main(String[] args) throws Exception {
        new DokuGenerator(StaticClass.class, StaticClass2.class);
    }

    public DokuGenerator(Class<?>... classesToDokument) throws Exception {
        List<Docu> documentAnnotations = getDocumentAnnotations(classesToDokument);
        printDocumentation(documentAnnotations);
    }

    private List<Docu> getDocumentAnnotations(Class<?>... classesToDokument)
            throws Exception {
        List<Docu> result = new ArrayList<Docu>();
        for (Class<?> c : classesToDokument)
            if (c.isAnnotationPresent(Docu.class))
                result.add(c.getAnnotation(Docu.class));
        return result;
    }

    private void printDocumentation(List<Docu> toDocument) {
        for (Docu m : toDocument)
            System.out.println(m.description());
    }

}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Docu {
    String description();
}

@Docu(description = "This is a static class!")
class StaticClass {
}

@Docu(description = "This is another static class!")
class StaticClass2 {
}

Impressions:

This is a static class!  
This is another static class!

Ce que nous voulons accomplir, est, qu'une classe ne peut pas seulement être staticly annoté, mais pouvez ajouter les informations d'exécution de la documentation. Nous sommes très heureux d'utiliser l' @Docu d'annotation la plupart du temps, mais il existe des cas particuliers que nous voulons spéciale documenation. On peut vouloir ajouter de la performance documenation pour certaines méthodes. Nous pouvons faire cela en laissant une classe implémente l'annotation. Le générateur vérifie d'abord pour l'annotation et, si non présent, il vérifie si la classe implémente l'annotation. Si c'est le cas, il ajoute de la classe à la liste d'annotations.

Comme ceci (seulement deux lignes de code supplémentaires dans le générateur):

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class DokuGenerator {

    public static void main(String[] args) throws Exception {
        new DokuGenerator(StaticClass.class, StaticClass2.class,
                DynamicClass.class);
    }

    public DokuGenerator(Class<?>... classesToDokument) throws Exception {
        List<Docu> documentAnnotations = getDocumentAnnotations(classesToDokument);
        printDocumentation(documentAnnotations);
    }

    private List<Docu> getDocumentAnnotations(Class<?>... classesToDokument)
            throws Exception {
        List<Docu> result = new ArrayList<Docu>();
        for (Class<?> c : classesToDokument)
            if (c.isAnnotationPresent(Docu.class))
                result.add(c.getAnnotation(Docu.class));
            else if (Arrays.asList(c.getInterfaces()).contains(Docu.class))
                result.add((Docu) c.newInstance());
        return result;
    }

    private void printDocumentation(List<Docu> toDocument) {
        for (Docu m : toDocument)
            System.out.println(m.description());
    }

}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Docu {
    String description();
}

@Docu(description = "This is a static class!")
class StaticClass {
}

@Docu(description = "This is another static class!")
class StaticClass2 {
}

class DynamicClass implements Docu {

    public DynamicClass() {
        try {
            Thread.sleep((long) (Math.random() * 100));
        } catch (InterruptedException e) {
            // ignore exception to make debugging a little harder
        }
    }

    @Override
    public String description() {
        long millis = System.currentTimeMillis();
        new DynamicClass();
        millis = System.currentTimeMillis() - millis;
        return "This is a dynamic class. I run on "
                + System.getProperty("os.name")
                + ". The construction of an instance of this class run for "
                + millis + " milliseconds.";
    }

    @Override
    public Class<? extends Annotation> annotationType() {
        return Docu.class;
    }

}

La sortie est:

This is a static class!  
This is another static class!  
This is a dynamic class. I run on Windows XP. The construction of an instance of this class run for 47 milliseconds.

Vous havn pas de changer le générateur de code que beaucoup parce que vous pouvez utiliser la classe en tant que remplacement de l'annotation.

Autre exemple, doit être un cadre qui utilise des annotations ou des XML de configuration. Vous pourriez avoir un processeur qui fonctionne sur les annotations. Si vous utilisez XML de configuration, vous pouvez générer des instances de classes qui implémentent les annotations et votre processeur travaille sur eux sans un seul changement! (bien sûr, il existe d'autres moyens pour accomplir le même effet, mais c'est UNE façon de le faire)

3voto

sfussenegger Points 16204

JAXBIntroductions est un bon exemple: il permet de configurer les annotations JAXB l'aide de fichiers XML. Deux principaux cas d'utilisation viennent à l'esprit: la configuration des classes, vous n'avez pas accès à la source ou des configurations différentes pour une seule classe.

En général, je pense que l'instanciation d'annotations de manière dynamique à les transmettre à des cadres est généralement un bon cas d'utilisation. Toutefois, si vous êtes le concepteur de ce cadre, je n'aurais certainement réfléchir à deux fois si.

0voto

ZXX Points 3216

Il n'y a pas d'utilisateur valide les cas, pour que le compilateur juste tollerates car il serait tout à fait désordre à l'interdisent et les gens qui sont de l'écriture de compilateurs peuvent avoir besoin de l'installation sur une occasion très rare. Si vous avez besoin de classer les annotations lisez cet article pour voir comment le faire: http://stackoverflow.com/questions/1624084/why-is-not-possible-to-extend-annotations-in-java

Inagine une pauvre âme qui vient après vous de maintenir et de débogage de code ou un autre qui a besoin d'écrire un codegen outil et suppose que annotatuion types sont droites ou un autre qui a juste utilisé une telle annotation même pas rêver de ce qui peut se passer et quoi faire à ce sujet. Au moment où il découvre que hack et trouve un moyen de l'éliminer, il va mourir de hernie ou équivalent mal :-) les Annotations devraient être purement énoncés déclaratifs, interprété uniquement par un codegen outil qui fonctionne séparément du code annoté et il les traite comme des données.

Prendre un nouveau regard sur le code et essayer de dire honnêtement ce qui est rationnel rason pour quelque chose comme:

 public Class<? extends Annotation> annotationType() { 
     return Id.class; 
 } 

et c'est encore peu de chose comparé à ce que les gens peuvent mettre dans le code.

Les Annotations ne sont pas le lieu de la pratique de piratage - qu'est ce que le compilateur essaie de véhiculer. Savez-vous exactement quand et comment le code dans la section "mise en œuvre" de l'annotation peut exécuter? Y compris CTOR? Ce qui est disponible et ce n'est pas à ce point? Ce qui est sûr pour vous appeler? Le compilateur n'a pas - il faudrait assez lourd analyse statique pour un compilateur pour vérifier la sécurité réelle de ces hack. Donc, au lieu de cela il a juste un avertissement, de sorte que, lorsque quelque chose va mal, les gens ne peut pas blâmer les compiler, VM et tout le reste.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X