web-dev-qa-db-fra.com

Fonctionnement de @Target (ElementType.ANNOTATION_TYPE)

Les annotations Java sont marquées d'une annotation @Target Pour déclarer les éventuels points de jointure qui peuvent être décorés par cette annotation. Les valeurs TYPE, FIELD, METHOD, etc. de l'énumération ElementType sont claires et simplement compréhensibles.

Question

POURQUOI pour utiliser la valeur @Target(ANNOTATION_TYPE)? À quoi servent les annotations annotées? Quelle est leur contribution? Donnez-moi un explication d'une idée comment cela fonctionne et pourquoi je devrais l'utiliser. Un exemple déjà existant et bien connu de son utilisation serait également très bien.

52
Gaim

Vous pouvez utiliser une annotation annotée pour créer une méta-annotation, par exemple, envisagez cette utilisation de @Transactional au printemps:

/**
 * Shortcut and more descriptive "alias" for {@code @Transactional(propagation = Propagation.MANDATORY)}.
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(propagation = Propagation.MANDATORY)
public @interface RequiresExistingTransaction {
}

Lorsque vous activez Spring pour traiter le @Transactional annotation, il recherchera les classes et méthodes qui portent @Transactionalo toute méta-annotation de celui-ci (une annotation qui est annotée avec @Transactional).

Quoi qu'il en soit, ce n'était qu'un exemple concret de la façon dont on peut utiliser une annotation annotée. Je suppose que ce sont principalement des frameworks comme Spring où il est logique de les utiliser.

36
zagyi

Chaque annotation annotée par @Target(ElementType.ANNOTATION_TYPE) est appelée Meta-annotation. Cela signifie que vous pouvez définir vos propres annotations personnalisées qui sont une fusion de nombreuses annotations combinées en une seule annotation pour créer composed annotations.

Un bon exemple de Android world est StringDef

Indique que l'élément String annoté représente un type logique et que sa valeur doit être l'une des constantes nommées explicitement.

@Retention(SOURCE)
@Target({ANNOTATION_TYPE})
public @interface StringDef {
    /** Defines the allowed constants for this element */
    String[] value() default {};
}
//--
@Retention(SOURCE)
@StringDef({POWER_SERVICE, WINDOW_SERVICE, LAYOUT_INFLATER_SERVICE}) 
public @interface ServicesName {}

public static final String POWER_SERVICE = "power";
public static final String WINDOW_SERVICE = "window";
public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
//--
@StringDef({SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY})
@Retention(RetentionPolicy.SOURCE)
public @interface WeekDays {}

public static final String SUNDAY = "sunday";
public static final String MONDAY = "monday";
public static final String TUESDAY = "tuesday";
public static final String WEDNESDAY = "wednesday";
public static final String THURSDAY = "thursday";
public static final String FRIDAY = "friday";
public static final String SATURDAY = "saturday";

...
public abstract Object getSystemService(@ServicesName String serviceName);
public abstract Object getDayOfWeek(@WeekDays String weekDay);

L'inspecteur de code traitera @ServicesName Et @WeekDays De la même manière que @StringDef. Par conséquent, nous pouvons créer autant de nomméStringDef que nécessaire et remplacer un ensemble de constantes. @Target(ElementType.ANNOTATION_TYPE) c'est un outil qui permet d'étendre l'utilisation des annotations.

5
yoAlex5

Par exemple, si l'annotation ressemble à

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

    String description() default "This is example for class annotation";
}

le compilateur complane dans cette situation

@SomeAnnotation
public class SomeClass {

    @SomeAnnotation    // here it's complaning
    public void someMethod(){}
}

Si vous changez

@Target(ElementType.TYPE) 

à

@Target({ElementType.METHOD, ElementType.TYPE}) 

il ne se plaindra plus.

2
Andrey