Annotazione Java - Java annotation
Nel linguaggio di programmazione Java , un'annotazione è una forma di metadati sintattici che possono essere aggiunti al codice sorgente Java . Classi , metodi , variabili , parametri e pacchetti Java possono essere annotati. Come i tag Javadoc , le annotazioni Java possono essere lette dai file di origine. A differenza dei tag Javadoc , le annotazioni Java possono anche essere incorporate e lette dai file di classe Java generati dal compilatore Java . Ciò consente alle annotazioni di essere conservate dalla macchina virtuale Java in fase di esecuzione e lette tramite reflection . È possibile creare meta-annotazioni da quelle esistenti in Java.
Storia
La piattaforma Java dispone di vari meccanismi di annotazione ad hoc , ad esempio il transientmodificatore o il @deprecatedtag javadoc. La richiesta di specifica Java JSR-175 ha introdotto la funzione di annotazione generica (nota anche come metadati ) nel processo della comunità Java nel 2002; ha ottenuto l'approvazione nel settembre 2004. Le annotazioni sono diventate disponibili nel linguaggio stesso a partire dalla versione 1.5 del Java Development Kit (JDK). Lo aptstrumento ha fornito un'interfaccia provvisoria per l'elaborazione delle annotazioni in fase di compilazione in JDK versione 1.5; JSR-269 lo ha formalizzato ed è stato integrato nel compilatore javac nella versione 1.6.
Annotazioni integrate
Java definisce una serie di annotazioni integrate nel linguaggio. Delle sette annotazioni standard, tre fanno parte di java.lang e le restanti quattro sono importate da java.lang.annotation.
Annotazioni applicate al codice Java:
-
@Override- Verifica che il metodo sia un override . Provoca un errore di compilazione se il metodo non viene trovato in una delle classi padre o nelle interfacce implementate . -
@Deprecated- Contrassegna il metodo come obsoleto. Causa un avviso di compilazione se viene utilizzato il metodo. -
@SuppressWarnings- Indica al compilatore di sopprimere gli avvisi relativi al tempo di compilazione specificati nei parametri di annotazione.
Annotazioni applicate ad altre annotazioni (note anche come "Meta annotazioni"):
-
@Retention- Specifica in che modo viene archiviata l'annotazione contrassegnata, se solo nel codice, compilata nella classe o disponibile in fase di esecuzione tramite reflection. -
@Documented- Segna un'altra annotazione da includere nella documentazione. -
@Target- Contrassegna un'altra annotazione per limitare il tipo di elementi Java a cui può essere applicata l'annotazione. -
@Inherited- Contrassegna un'altra annotazione da ereditare alle sottoclassi della classe annotata (per impostazione predefinita le annotazioni non vengono ereditate dalle sottoclassi).
Da Java 7, al linguaggio sono state aggiunte tre annotazioni aggiuntive.
-
@SafeVarargs- Sopprime gli avvisi per tutti i chiamanti di un metodo o costruttore con un parametro generics varargs , da Java 7. -
@FunctionalInterface- Specifica che la dichiarazione del tipo deve essere un'interfaccia funzionale , a partire da Java 8. -
@Repeatable- Specifica che l'annotazione può essere applicata più di una volta alla stessa dichiarazione, da Java 8.
Esempio
Annotazioni integrate
Questo esempio dimostra l'uso @Overridedell'annotazione. Indica al compilatore di controllare le classi padre per i metodi corrispondenti. In questo caso viene generato un errore perché il gettype()metodo della classe Cat non sovrascrive getType()di fatto la classe Animal like è desiderato, a causa del mismatching case . Se l' @Overrideannotazione fosse assente, gettype()verrebbe creato un nuovo metodo di nome nella classe Cat.
public class Animal {
public void speak() {
}
public String getType() {
return "Generic animal";
}
}
public class Cat extends Animal {
@Override
public void speak() { // This is a good override.
System.out.println("Meow.");
}
@Override
public String gettype() { // Compile-time error due to typo: should be getType() not gettype().
return "Cat";
}
}
Annotazioni personalizzate
Le dichiarazioni del tipo di annotazione sono simili alle normali dichiarazioni di interfaccia. Una chiocciola (@) precede la parola chiave dell'interfaccia . Ogni dichiarazione di metodo definisce un elemento del tipo di annotazione. Le dichiarazioni di metodo non devono avere parametri o una clausola throws. I tipi restituiti sono limitati a primitive , String , Class, enums , annotazioni e array dei tipi precedenti. I metodi possono avere valori predefiniti .
// @Twizzle is an annotation to method toggle().
@Twizzle
public void toggle() {
}
// Declares the annotation Twizzle.
public @interface Twizzle {
}
Le annotazioni possono includere un elenco facoltativo di coppie chiave-valore:
// Same as: @Edible(value = true)
@Edible(true)
Item item = new Carrot();
public @interface Edible {
boolean value() default false;
}
@Author(first = "Oompah", last = "Loompah")
Book book = new Book();
public @interface Author {
String first();
String last();
}
Le annotazioni stesse possono essere annotate per indicare dove e quando possono essere utilizzate:
@Retention(RetentionPolicy.RUNTIME) // Make this annotation accessible at runtime via reflection.
@Target({ElementType.METHOD}) // This annotation can only be applied to class methods.
public @interface Tweezable {
}
Il compilatore riserva una serie di annotazioni speciali (incluse @Deprecated, @Overridee @SuppressWarnings) per scopi sintattici.
Le annotazioni vengono spesso utilizzate dai framework come un modo per applicare convenientemente comportamenti a classi e metodi definiti dall'utente che devono essere altrimenti dichiarati in un'origine esterna (come un file di configurazione XML) o a livello di codice (con chiamate API). La seguente, ad esempio, è una classe di dati JPA annotata :
@Entity // Declares this an entity bean
@Table(name = "people") // Maps the bean to SQL table "people"
public class Person implements Serializable {
@Id // Map this to the primary key column.
@GeneratedValue(strategy = GenerationType.AUTO) // Database will generate new primary keys, not us.
private Integer id;
@Column(length = 32) // Truncate column values to 32 characters.
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Le annotazioni non sono chiamate di metodo e, da sole, non faranno nulla. Piuttosto, l'oggetto classe viene passato all'implementazione JPA in fase di esecuzione , che quindi estrae le annotazioni per generare una mappatura relazionale oggetto .
Di seguito viene fornito un esempio completo:
package com.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD,
ElementType.CONSTRUCTOR,ElementType.ANNOTATION_TYPE,
ElementType.PACKAGE,ElementType.FIELD,ElementType.LOCAL_VARIABLE})
@Inherited
public @interface Unfinished {
public enum Priority { LOW, MEDIUM, HIGH }
String value();
String[] changedBy() default "";
String[] lastChangedBy() default "";
Priority priority() default Priority.MEDIUM;
String createdBy() default "James Gosling";
String lastChanged() default "2011-07-08";
}
package com.annotation;
public @interface UnderConstruction {
String owner() default "Patrick Naughton";
String value() default "Object is Under Construction.";
String createdBy() default "Mike Sheridan";
String lastChanged() default "2011-07-08";
}
package com.validators;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import com.annotation.UnderConstruction;
import com.annotation.Unfinished;
import com.annotation.Unfinished.Priority;
import com.util.Util;
@UnderConstruction(owner="Jon Doe")
public class DateValidator implements Validator {
public void validate(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
String date = (String) value;
String errorLabel = "Please enter a valid date.";
if (!component.getAttributes().isEmpty()) {
errorLabel = (String) component.getAttributes().get("errordisplayval");
}
if (!Util.validateAGivenDate(date)) {
@Unfinished(changedBy = "Steve",
value = "whether to add message to context or not, confirm",
priority = Priority.HIGH
)
FacesMessage message = new FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_ERROR);
message.setSummary(errorLabel);
message.setDetail(errorLabel);
throw new ValidatorException(message);
}
}
}
in lavorazione
Quando il codice sorgente Java viene compilato, le annotazioni possono essere elaborate dai plug-in del compilatore chiamati processori di annotazione. I processori possono produrre messaggi informativi o creare risorse o file sorgente Java aggiuntivi, che a loro volta possono essere compilati ed elaborati. Tuttavia, i processori di annotazione non possono modificare il codice annotato stesso. (Modifiche di codice possono essere implementate con metodi al di là del linguaggio Java Specification). Il compilatore Java memorizza condizionalmente metadati annotazione nei file di classe, se l'annotazione ha una RetentionPolicydi CLASSo RUNTIME. Successivamente, la JVM o altri programmi possono cercare i metadati per determinare come interagire con gli elementi del programma o modificarne il comportamento.
Oltre a elaborare un'annotazione utilizzando un processore di annotazioni, un programmatore Java può scrivere il proprio codice che utilizza le riflessioni per elaborare l'annotazione. Java SE 5 supporta una nuova interfaccia definita nel java.lang.reflectpacchetto. Questo pacchetto contiene l'interfaccia chiamata AnnotatedElementche viene implementata dalle classi Java di riflessione tra cui Class, Constructor, Field, Method, e Package. Le implementazioni di questa interfaccia vengono utilizzate per rappresentare un elemento annotato del programma attualmente in esecuzione nella Java Virtual Machine. Questa interfaccia consente di leggere le annotazioni in modo riflessivo.
L' AnnotatedElementinterfaccia fornisce l'accesso alle annotazioni con RUNTIMEconservazione. Questo accesso è fornito dai metodi getAnnotation, getAnnotations, e isAnnotationPresent. Poiché i tipi di annotazione sono compilati e archiviati in file di codice byte proprio come le classi, le annotazioni restituite da questi metodi possono essere interrogate proprio come qualsiasi normale oggetto Java. Di seguito viene fornito un esempio completo di elaborazione di un'annotazione:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// This is the annotation to be processed
// Default for Target is all Java Elements
// Change retention policy to RUNTIME (default is CLASS)
@Retention(RetentionPolicy.RUNTIME)
public @interface TypeHeader {
// Default value specified for developer attribute
String developer() default "Unknown";
String lastModified();
String [] teamMembers();
int meaningOfLife();
}
// This is the annotation being applied to a class
@TypeHeader(developer = "Bob Bee",
lastModified = "2013-02-12",
teamMembers = { "Ann", "Dan", "Fran" },
meaningOfLife = 42)
public class SetCustomAnnotation {
// Class contents go here
}
// This is the example code that processes the annotation
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
public class UseCustomAnnotation {
public static void main(String [] args) {
Class<SetCustomAnnotation> classObject = SetCustomAnnotation.class;
readAnnotation(classObject);
}
static void readAnnotation(AnnotatedElement element) {
try {
System.out.println("Annotation element values: \n");
if (element.isAnnotationPresent(TypeHeader.class)) {
// getAnnotation returns Annotation type
Annotation singleAnnotation =
element.getAnnotation(TypeHeader.class);
TypeHeader header = (TypeHeader) singleAnnotation;
System.out.println("Developer: " + header.developer());
System.out.println("Last Modified: " + header.lastModified());
// teamMembers returned as String []
System.out.print("Team members: ");
for (String member : header.teamMembers())
System.out.print(member + ", ");
System.out.print("\n");
System.out.println("Meaning of Life: "+ header.meaningOfLife());
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
Utilizzo in natura
I ricercatori hanno studiato l'utilizzo delle annotazioni Java su 1.094 notevoli progetti Java open source ospitati su GitHub. Hanno scoperto che le annotazioni vengono mantenute attivamente, con l'aggiunta di molte annotazioni, ma anche modificate o rimosse a causa di bug nel tipo o nei valori di annotazione. Nel complesso, questo studio rileva che esiste una piccola ma significativa relazione tra l'utilizzo delle annotazioni e la propensione agli errori del codice: il codice Java con annotazioni tende ad essere meno soggetto a errori.
Guarda anche
- JSR 250: annotazioni comuni per la piattaforma Java
- Attributi CLI
- Programmazione Java
- Macchina virtuale Java
- Architettura basata sul modello
- Decoratori Python , ispirati alle annotazioni Java, che hanno una sintassi simile.
Riferimenti
link esterno
- Introduzione a Java 6 Annotazioni sul sito Sun Developer Network
- Introduzione alle annotazioni Java di MM Islam Chisty
- Introduzione a Java 5.0 Annotazioni di Joy Christy
- Of Java Annotations di John Hunt
- Annotazioni personalizzate in Java
- Spiegazione delle annotazioni Java
- Comprensione delle annotazioni in Java